diff --git a/app/build.gradle b/app/build.gradle deleted file mode 100644 index 1e0d323..0000000 --- a/app/build.gradle +++ /dev/null @@ -1,81 +0,0 @@ -apply plugin: 'com.android.application' - -android { - lintOptions { - abortOnError false - } - - /* signingConfigs { - release { - keyAlias 'key' - keyPassword '123456' - storeFile file('D:/AndroidWork/ImageCompress/key.jks') - storePassword '123456' - } - }*/ - defaultConfig { - def versions = rootProject.ext.android - compileSdkVersion versions.compileSdkVersion - applicationId "com.baixiaohu.imagecompress" - minSdkVersion versions.minSdkVersion - targetSdkVersion versions.targetSdkVersion - versionCode versions.versionCode - versionName versions.versionName - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - buildToolsVersion versions.buildToolsVersion - } - buildTypes { - release { - // signingConfig signingConfigs.release - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - buildConfigField("boolean", "IS_DEBUG", "false") - //是否清理无用资源 - //shrinkResources true - //是否启用zipAlign压缩 - zipAlignEnabled true - pseudoLocalesEnabled true - } - /* debug{ - // signingConfig signingConfigs.release - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - buildConfigField("boolean","IS_DEBUG","true") - //是否清理无用资源 - shrinkResources true - //是否启用zipAlign压缩 - zipAlignEnabled true - pseudoLocalesEnabled true - }*/ - } -} - -dependencies { - implementation fileTree(include: ['*.jar'], dir: 'libs') - def versions = rootProject.ext.dependencies - //noinspection GradleCompatible - implementation versions.appcompatV7 - implementation versions.constraint - implementation 'com.android.support.constraint:constraint-layout:1.1.3' - testImplementation versions.junit - androidTestImplementation versions.runner - androidTestImplementation versions.espresso - implementation versions.glide - implementation versions.design - implementation project(':compress') - implementation files('libs/systembartint-1.0.4.jar') - implementation versions.PhotoView - implementation versions.multidex - debugImplementation versions.leakcanaryAndroid - releaseImplementation versions.leakcanaryAndroidNoOp - debugImplementation versions.leakcanarySupportFragment - implementation versions.supportV4 - implementation versions.rxlifecycleComponents - implementation project(':matisse') -} -allprojects { - repositories { - jcenter() - maven { url "https://jitpack.io" } - } -} diff --git a/app/release/output.json b/app/release/output.json deleted file mode 100644 index 09be9c0..0000000 --- a/app/release/output.json +++ /dev/null @@ -1 +0,0 @@ -[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":1},"path":"app-release.apk","properties":{"packageId":"com.baixiaohu.imagecompress","split":"","minSdkVersion":"15"}}] \ No newline at end of file diff --git a/app/src/main/java/com/baixiaohu/imagecompress/activity/MainActivity.java b/app/src/main/java/com/baixiaohu/imagecompress/activity/MainActivity.java index 66c9b71..c1772fe 100644 --- a/app/src/main/java/com/baixiaohu/imagecompress/activity/MainActivity.java +++ b/app/src/main/java/com/baixiaohu/imagecompress/activity/MainActivity.java @@ -10,8 +10,6 @@ import com.baixiaohu.imagecompress.dialog.ExitDialog; import com.baixiaohu.imagecompress.permission.imp.OnPermissionsResult; import com.baixiaohu.imagecompress.toast.Toasts; -import com.bumptech.glide.Glide; -import com.squareup.haha.perflib.Main; import java.util.List; diff --git a/app/src/main/java/com/baixiaohu/imagecompress/base/CameraActivity.java b/app/src/main/java/com/baixiaohu/imagecompress/base/CameraActivity.java index e684364..c318817 100644 --- a/app/src/main/java/com/baixiaohu/imagecompress/base/CameraActivity.java +++ b/app/src/main/java/com/baixiaohu/imagecompress/base/CameraActivity.java @@ -11,9 +11,9 @@ import com.baixiaohu.imagecompress.dialog.PhotoDialog; import com.baixiaohu.imagecompress.permission.imp.OnPermissionsResult; import com.baixiaohu.imagecompress.toast.Toasts; -import com.zhihu.matisse.Matisse; -import com.zhihu.matisse.MimeType; -import com.zhihu.matisse.engine.impl.GlideEngine; +import com.example.media.MediaSelector; +import com.example.media.bean.MediaSelectorFile; +import com.example.media.resolver.Contast; import java.io.File; import java.io.IOException; @@ -121,14 +121,7 @@ public void onClickCancel(View view) { } protected void openZhiHuAlbum() { - Matisse.from(this) - .choose(MimeType.ofImage()) - .countable(true) - .maxSelectable(9) - .restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) - .thumbnailScale(0.85f) - .imageEngine(new GlideEngine()) - .forResult(REQUEST_CODE_CHOOSE); + MediaSelector.with(this).openMediaActivity(); } @Override @@ -163,16 +156,16 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { imageFileResult(bean); } - } else if (requestCode == REQUEST_CODE_CHOOSE) { - List pathData = Matisse.obtainPathResult(data); - if (pathData == null || pathData.size() == 0) + } + break; + case Contast.CODE_RESULT_MEDIA: + if (requestCode == Contast.CODE_REQUEST_MEDIA) { + List mediaData = MediaSelector.resultMediaFile(data); + if (mediaData == null || mediaData.size() == 0) return; List imageFileBeanList = new ArrayList<>(); - for (String path : pathData) { - if (path == null) { - return; - } - File file = new File(path); + for (MediaSelectorFile mediaSelectorFile : mediaData) { + File file = new File(mediaSelectorFile.filePath); if (FileUtils.isImageFile(file)) { ImageFileBean imageFileBean = new ImageFileBean(); imageFileBean.isImage = true; @@ -185,6 +178,7 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { imageFilesResult(imageFileBeanList); } break; + default: break; } diff --git a/compress/src/main/java/utils/CompressPicker.java b/compress/src/main/java/utils/CompressPicker.java index 3f753a3..746c38d 100644 --- a/compress/src/main/java/utils/CompressPicker.java +++ b/compress/src/main/java/utils/CompressPicker.java @@ -1,10 +1,14 @@ package utils; +import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.ImageDecoder; import android.graphics.Matrix; +import android.graphics.drawable.AnimatedImageDrawable; import android.media.ExifInterface; +import android.os.Build; import android.support.annotation.NonNull; @@ -41,43 +45,64 @@ public class CompressPicker { * @param imageConfig bean * @return 返回Bitmap */ - public static Bitmap compressBitmap(ImageConfig imageConfig) { + public static Bitmap compressBitmap(final ImageConfig imageConfig) { Bitmap bitmap = null; if (null != imageConfig) { - CompressPicker.mImageConfig = imageConfig; - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inPreferredConfig = imageConfig.config; - options.inJustDecodeBounds = true; - BitmapFactory.decodeFile(imageConfig.imagePath, options); - options.inSampleSize = (int) ((options.outWidth * 1.0f) / (imageConfig.compressWidth * 1.0f) + (options.outHeight * 1.0f) / (imageConfig.compressHeight * 1.0f)) / 2; - options.inJustDecodeBounds = false; - options.inScaled = false; - options.inMutable = true; - bitmap = BitmapFactory.decodeFile(imageConfig.imagePath, options); - ExifInterface exif; - try { - exif = new ExifInterface(imageConfig.imagePath); - int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0); - Matrix matrix = new Matrix(); - switch (orientation) { - case ExifInterface.ORIENTATION_ROTATE_90: - matrix.postRotate(90); - break; - case ExifInterface.ORIENTATION_ROTATE_180: - matrix.postRotate(180); - break; - case ExifInterface.ORIENTATION_ROTATE_270: - matrix.postRotate(270); - break; - default: - break; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + ImageDecoder.Source source = ImageDecoder.createSource(new File(imageConfig.imagePath)); + try { + bitmap = ImageDecoder.decodeBitmap(source, new ImageDecoder.OnHeaderDecodedListener() { + @Override + public void onHeaderDecoded(ImageDecoder decoder, ImageDecoder.ImageInfo info, ImageDecoder.Source source) { + decoder.setTargetSize(imageConfig.compressWidth, imageConfig.compressHeight); + decoder.setTargetSampleSize(150*1024); + decoder.setMutableRequired(true); + decoder.close(); + } + }); + } catch (IOException e) { + e.printStackTrace(); } - bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); - } catch (IOException e) { - e.printStackTrace(); - return bitmap; + } else { + CompressPicker.mImageConfig = imageConfig; + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inPreferredConfig = imageConfig.config; + options.inJustDecodeBounds = true; + BitmapFactory.decodeFile(imageConfig.imagePath, options); + options.inSampleSize = (int) ((options.outWidth * 1.0f) / (imageConfig.compressWidth * 1.0f) + (options.outHeight * 1.0f) / (imageConfig.compressHeight * 1.0f)) / 2; + options.inJustDecodeBounds = false; + options.inScaled = false; + options.inMutable = true; + bitmap = BitmapFactory.decodeFile(imageConfig.imagePath, options); + } + if (bitmap != null) { + ExifInterface exif; + try { + exif = new ExifInterface(imageConfig.imagePath); + int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0); + Matrix matrix = new Matrix(); + switch (orientation) { + case ExifInterface.ORIENTATION_ROTATE_90: + matrix.postRotate(90); + break; + case ExifInterface.ORIENTATION_ROTATE_180: + matrix.postRotate(180); + break; + case ExifInterface.ORIENTATION_ROTATE_270: + matrix.postRotate(270); + break; + default: + break; + } + bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); + } catch (IOException e) { + e.printStackTrace(); + return bitmap; + } } + + } return bitmap; } diff --git a/config.gradle b/config.gradle index b5d5681..0e94cdd 100644 --- a/config.gradle +++ b/config.gradle @@ -1,33 +1,36 @@ ext { android = [ - compileSdkVersion: 27, + compileSdkVersion: 28, minSdkVersion : 15, - targetSdkVersion : 27, + targetSdkVersion : 28, versionCode : 1, versionName : "1.0", - buildToolsVersion: "27.0.3" + buildToolsVersion: "28.0.0" ] dependVersion = [ - appcompat : "27.1.1", + appcompat : "28.0.0", constraint : "1.0.2", junit : "4.12", runner : "1.0.1", espresso : "3.0.1", glide : "4.8.0", - design : "27.1.1", + design : "28.0.0", PhotoView : "2.0.0", multidex : "1.0.3", leakcanaryAndroid : "1.6.1", leakcanaryAndroidNoOp : "1.6.1", leakcanarySupportFragment: "1.6.1", - supportV4 : "27.1.1", + supportV4 : "28.0.0", rxjava : "2.0.0", rxandroid : "2.0.0", rxlifecycleComponents : "2.1.0", - recyclerview : "27.0.0", + recyclerview : "28.0.0", imagezoom : "1.0.4", - picasso : "2.5.2" + picasso : "2.5.2", + projectview : "1.0.1", + eventbus : "3.1.1", + ucrop : "2.2.2" ] @@ -50,7 +53,10 @@ ext { rxlifecycleComponents : "com.trello.rxlifecycle2:rxlifecycle-components:${dependVersion.rxlifecycleComponents}", recyclerview : "com.android.support:recyclerview-v7:${dependVersion.recyclerview}", imagezoom : "it.sephiroth.android.library.imagezoom:library:${dependVersion.imagezoom}", - picasso : "com.squareup.picasso:picasso:${dependVersion.picasso}" + picasso : "com.squareup.picasso:picasso:${dependVersion.picasso}", + projectview : "com.github.Hu12037102:ProjectView:${dependVersion.projectview}", + eventbus : "org.greenrobot:eventbus:${dependVersion.eventbus}", + ucrop : "com.github.yalantis:ucrop:${dependVersion.ucrop}" // rxlifecycleComponents:"com.trello.rxlifecycle2:rxlifecycle-android:${dependVersion.rxlifecycleComponents}" //implementation 'com.trello.rxlifecycle2:rxlifecycle-android:2.2.2' diff --git a/matisse/build.gradle b/matisse/build.gradle deleted file mode 100644 index 487d8bb..0000000 --- a/matisse/build.gradle +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -apply plugin: 'com.android.library' -apply plugin: 'checkstyle' - -/*android { - compileSdkVersion 27 - buildToolsVersion '27.0.3' - - defaultConfig { - minSdkVersion 14 - targetSdkVersion 27 - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_7 - targetCompatibility JavaVersion.VERSION_1_7 - } - lintOptions { - abortOnError false - } -}*/ - - -android { - - defaultConfig { - def versions = rootProject.ext.android - compileSdkVersion versions.compileSdkVersion - minSdkVersion versions.minSdkVersion - targetSdkVersion versions.targetSdkVersion - versionCode versions.versionCode - versionName versions.versionName - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - buildToolsVersion versions.buildToolsVersion - } - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - } -} - - - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) - def versions = rootProject.ext.dependencies - implementation versions.appcompatV7 - implementation versions.supportV4 - //implementation "com.android.support:support-annotations:${supportLibVersion}" - implementation versions.recyclerview - implementation versions.imagezoom - - compileOnly versions.glide - compileOnly versions.picasso -} - - - - - - -// jcenter configuration for novoda's bintray-release -// $ ./gradlew clean build bintrayUpload -PbintrayUser=BINTRAY_USERNAME -PbintrayKey=BINTRAY_KEY -PdryRun=false - - -/* -task javadoc(type: Javadoc) { - options.encoding = "utf-8" -} - -checkstyle { - toolVersion = '7.6.1' -} - -tasks.withType(Javadoc) { - options.addStringOption('Xdoclint:none', '-quiet') - options.addStringOption('encoding', 'UTF-8') -} - -task checkstyle(type:Checkstyle) { - description 'Runs Checkstyle inspection against matisse sourcesets.' - group = 'Code Quality' - configFile rootProject.file('checkstyle.xml') - ignoreFailures = false - showViolations true - classpath = files() - source 'src/main/java' -}*/ diff --git a/matisse/gradle.properties b/matisse/gradle.properties deleted file mode 100644 index e69de29..0000000 diff --git a/matisse/proguard-rules.pro b/matisse/proguard-rules.pro deleted file mode 100644 index f1ffffd..0000000 --- a/matisse/proguard-rules.pro +++ /dev/null @@ -1,19 +0,0 @@ -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in /Library/android-sdk-macosx/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the ProGuard -# include property in project.properties. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# Add any project specific keep options here: - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - --dontwarn com.squareup.okhttp.** diff --git a/matisse/src/main/AndroidManifest.xml b/matisse/src/main/AndroidManifest.xml deleted file mode 100644 index 7057835..0000000 --- a/matisse/src/main/AndroidManifest.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/matisse/src/main/java/com/zhihu/matisse/Matisse.java b/matisse/src/main/java/com/zhihu/matisse/Matisse.java deleted file mode 100644 index 7476321..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/Matisse.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse; - -import android.app.Activity; -import android.content.Intent; -import android.net.Uri; -import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; - -import com.zhihu.matisse.ui.MatisseActivity; - -import java.lang.ref.WeakReference; -import java.util.List; -import java.util.Set; - -/** - * Entry for Matisse's media selection. - */ -public final class Matisse { - - private final WeakReference mContext; - private final WeakReference mFragment; - - private Matisse(Activity activity) { - this(activity, null); - } - - private Matisse(Fragment fragment) { - this(fragment.getActivity(), fragment); - } - - private Matisse(Activity activity, Fragment fragment) { - mContext = new WeakReference<>(activity); - mFragment = new WeakReference<>(fragment); - } - - /** - * Start Matisse from an Activity. - *

- * This Activity's {@link Activity#onActivityResult(int, int, Intent)} will be called when user - * finishes selecting. - * - * @param activity Activity instance. - * @return Matisse instance. - */ - public static Matisse from(Activity activity) { - return new Matisse(activity); - } - - /** - * Start Matisse from a Fragment. - *

- * This Fragment's {@link Fragment#onActivityResult(int, int, Intent)} will be called when user - * finishes selecting. - * - * @param fragment Fragment instance. - * @return Matisse instance. - */ - public static Matisse from(Fragment fragment) { - return new Matisse(fragment); - } - - /** - * Obtain user selected media' {@link Uri} list in the starting Activity or Fragment. - * - * @param data Intent passed by {@link Activity#onActivityResult(int, int, Intent)} or - * {@link Fragment#onActivityResult(int, int, Intent)}. - * @return User selected media' {@link Uri} list. - */ - public static List obtainResult(Intent data) { - return data.getParcelableArrayListExtra(MatisseActivity.EXTRA_RESULT_SELECTION); - } - - /** - * Obtain user selected media path list in the starting Activity or Fragment. - * - * @param data Intent passed by {@link Activity#onActivityResult(int, int, Intent)} or - * {@link Fragment#onActivityResult(int, int, Intent)}. - * @return User selected media path list. - */ - public static List obtainPathResult(Intent data) { - return data.getStringArrayListExtra(MatisseActivity.EXTRA_RESULT_SELECTION_PATH); - } - - /** - * Obtain state whether user decide to use selected media in original - * - * @param data Intent passed by {@link Activity#onActivityResult(int, int, Intent)} or - * {@link Fragment#onActivityResult(int, int, Intent)}. - * @return Whether use original photo - */ - public static boolean obtainOriginalState(Intent data) { - return data.getBooleanExtra(MatisseActivity.EXTRA_RESULT_ORIGINAL_ENABLE, false); - } - - /** - * MIME types the selection constrains on. - *

- * Types not included in the set will still be shown in the grid but can't be chosen. - * - * @param mimeTypes MIME types set user can choose from. - * @return {@link SelectionCreator} to build select specifications. - * @see MimeType - * @see SelectionCreator - */ - public SelectionCreator choose(Set mimeTypes) { - return this.choose(mimeTypes, true); - } - - /** - * MIME types the selection constrains on. - *

- * Types not included in the set will still be shown in the grid but can't be chosen. - * - * @param mimeTypes MIME types set user can choose from. - * @param mediaTypeExclusive Whether can choose images and videos at the same time during one single choosing - * process. true corresponds to not being able to choose images and videos at the same - * time, and false corresponds to being able to do this. - * @return {@link SelectionCreator} to build select specifications. - * @see MimeType - * @see SelectionCreator - */ - public SelectionCreator choose(Set mimeTypes, boolean mediaTypeExclusive) { - return new SelectionCreator(this, mimeTypes, mediaTypeExclusive); - } - - @Nullable - Activity getActivity() { - return mContext.get(); - } - - @Nullable - Fragment getFragment() { - return mFragment != null ? mFragment.get() : null; - } - -} diff --git a/matisse/src/main/java/com/zhihu/matisse/MimeType.java b/matisse/src/main/java/com/zhihu/matisse/MimeType.java deleted file mode 100644 index 9c199d3..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/MimeType.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (C) 2014 nohana, Inc. - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse; - -import android.content.ContentResolver; -import android.net.Uri; -import android.text.TextUtils; -import android.support.v4.util.ArraySet; -import android.webkit.MimeTypeMap; - -import com.zhihu.matisse.internal.utils.PhotoMetadataUtils; - -import java.util.Arrays; -import java.util.EnumSet; -import java.util.Locale; -import java.util.Set; - -/** - * MIME Type enumeration to restrict selectable media on the selection activity. Matisse only supports images and - * videos. - *

- * Good example of mime types Android supports: - * https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/media/java/android/media/MediaFile.java - */ -@SuppressWarnings("unused") -public enum MimeType { - - // ============== images ============== - JPEG("image/jpeg", arraySetOf( - "jpg", - "jpeg" - )), - PNG("image/png", arraySetOf( - "png" - )), - GIF("image/gif", arraySetOf( - "gif" - )), - BMP("image/x-ms-bmp", arraySetOf( - "bmp" - )), - WEBP("image/webp", arraySetOf( - "webp" - )), - - // ============== videos ============== - MPEG("video/mpeg", arraySetOf( - "mpeg", - "mpg" - )), - MP4("video/mp4", arraySetOf( - "mp4", - "m4v" - )), - QUICKTIME("video/quicktime", arraySetOf( - "mov" - )), - THREEGPP("video/3gpp", arraySetOf( - "3gp", - "3gpp" - )), - THREEGPP2("video/3gpp2", arraySetOf( - "3g2", - "3gpp2" - )), - MKV("video/x-matroska", arraySetOf( - "mkv" - )), - WEBM("video/webm", arraySetOf( - "webm" - )), - TS("video/mp2ts", arraySetOf( - "ts" - )), - AVI("video/avi", arraySetOf( - "avi" - )); - - private final String mMimeTypeName; - private final Set mExtensions; - - MimeType(String mimeTypeName, Set extensions) { - mMimeTypeName = mimeTypeName; - mExtensions = extensions; - } - - public static Set ofAll() { - return EnumSet.allOf(MimeType.class); - } - - public static Set of(MimeType type, MimeType... rest) { - return EnumSet.of(type, rest); - } - - public static Set ofImage() { - return EnumSet.of(JPEG, PNG, GIF, BMP, WEBP); - } - - public static Set ofVideo() { - return EnumSet.of(MPEG, MP4, QUICKTIME, THREEGPP, THREEGPP2, MKV, WEBM, TS, AVI); - } - - private static Set arraySetOf(String... suffixes) { - return new ArraySet<>(Arrays.asList(suffixes)); - } - - @Override - public String toString() { - return mMimeTypeName; - } - - public boolean checkType(ContentResolver resolver, Uri uri) { - MimeTypeMap map = MimeTypeMap.getSingleton(); - if (uri == null) { - return false; - } - String type = map.getExtensionFromMimeType(resolver.getType(uri)); - String path = null; - // lazy load the path and prevent resolve for multiple times - boolean pathParsed = false; - for (String extension : mExtensions) { - if (extension.equals(type)) { - return true; - } - if (!pathParsed) { - // we only resolve the path for one time - path = PhotoMetadataUtils.getPath(resolver, uri); - if (!TextUtils.isEmpty(path)) { - path = path.toLowerCase(Locale.US); - } - pathParsed = true; - } - if (path != null && path.endsWith(extension)) { - return true; - } - } - return false; - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/SelectionCreator.java b/matisse/src/main/java/com/zhihu/matisse/SelectionCreator.java deleted file mode 100644 index beb622c..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/SelectionCreator.java +++ /dev/null @@ -1,367 +0,0 @@ -/* - * Copyright (C) 2014 nohana, Inc. - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse; - -import android.app.Activity; -import android.content.Intent; -import android.os.Build; -import android.support.annotation.IntDef; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.RequiresApi; -import android.support.annotation.StyleRes; -import android.support.v4.app.Fragment; - -import com.zhihu.matisse.engine.ImageEngine; -import com.zhihu.matisse.filter.Filter; -import com.zhihu.matisse.internal.entity.CaptureStrategy; -import com.zhihu.matisse.internal.entity.SelectionSpec; -import com.zhihu.matisse.listener.OnCheckedListener; -import com.zhihu.matisse.listener.OnSelectedListener; -import com.zhihu.matisse.ui.MatisseActivity; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.Set; - -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_FULL_USER; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT; - -/** - * Fluent API for building media select specification. - */ -@SuppressWarnings("unused") -public final class SelectionCreator { - private final Matisse mMatisse; - private final SelectionSpec mSelectionSpec; - - @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) - @IntDef({ - SCREEN_ORIENTATION_UNSPECIFIED, - SCREEN_ORIENTATION_LANDSCAPE, - SCREEN_ORIENTATION_PORTRAIT, - SCREEN_ORIENTATION_USER, - SCREEN_ORIENTATION_BEHIND, - SCREEN_ORIENTATION_SENSOR, - SCREEN_ORIENTATION_NOSENSOR, - SCREEN_ORIENTATION_SENSOR_LANDSCAPE, - SCREEN_ORIENTATION_SENSOR_PORTRAIT, - SCREEN_ORIENTATION_REVERSE_LANDSCAPE, - SCREEN_ORIENTATION_REVERSE_PORTRAIT, - SCREEN_ORIENTATION_FULL_SENSOR, - SCREEN_ORIENTATION_USER_LANDSCAPE, - SCREEN_ORIENTATION_USER_PORTRAIT, - SCREEN_ORIENTATION_FULL_USER, - SCREEN_ORIENTATION_LOCKED - }) - @Retention(RetentionPolicy.SOURCE) - @interface ScreenOrientation { - } - - /** - * Constructs a new specification builder on the context. - * - * @param matisse a requester context wrapper. - * @param mimeTypes MIME type set to select. - */ - SelectionCreator(Matisse matisse, @NonNull Set mimeTypes, boolean mediaTypeExclusive) { - mMatisse = matisse; - mSelectionSpec = SelectionSpec.getCleanInstance(); - mSelectionSpec.mimeTypeSet = mimeTypes; - mSelectionSpec.mediaTypeExclusive = mediaTypeExclusive; - mSelectionSpec.orientation = SCREEN_ORIENTATION_UNSPECIFIED; - } - - /** - * Whether to show only one media type if choosing medias are only images or videos. - * - * @param showSingleMediaType whether to show only one media type, either images or videos. - * @return {@link SelectionCreator} for fluent API. - * @see SelectionSpec#onlyShowImages() - * @see SelectionSpec#onlyShowVideos() - */ - public SelectionCreator showSingleMediaType(boolean showSingleMediaType) { - mSelectionSpec.showSingleMediaType = showSingleMediaType; - return this; - } - - /** - * Theme for media selecting Activity. - *

- * There are two built-in themes: - * 1. com.zhihu.matisse.R.style.Matisse_Zhihu; - * 2. com.zhihu.matisse.R.style.Matisse_Dracula - * you can define a custom theme derived from the above ones or other themes. - * - * @param themeId theme resource id. Default value is com.zhihu.matisse.R.style.Matisse_Zhihu. - * @return {@link SelectionCreator} for fluent API. - */ - public SelectionCreator theme(@StyleRes int themeId) { - mSelectionSpec.themeId = themeId; - return this; - } - - /** - * Show a auto-increased number or a check mark when user select media. - * - * @param countable true for a auto-increased number from 1, false for a check mark. Default - * value is false. - * @return {@link SelectionCreator} for fluent API. - */ - public SelectionCreator countable(boolean countable) { - mSelectionSpec.countable = countable; - return this; - } - - /** - * Maximum selectable count. - * - * @param maxSelectable Maximum selectable count. Default value is 1. - * @return {@link SelectionCreator} for fluent API. - */ - public SelectionCreator maxSelectable(int maxSelectable) { - if (maxSelectable < 1) - throw new IllegalArgumentException("maxSelectable must be greater than or equal to one"); - if (mSelectionSpec.maxImageSelectable > 0 || mSelectionSpec.maxVideoSelectable > 0) - throw new IllegalStateException("already set maxImageSelectable and maxVideoSelectable"); - mSelectionSpec.maxSelectable = maxSelectable; - return this; - } - - /** - * Only useful when {@link SelectionSpec#mediaTypeExclusive} set true and you want to set different maximum - * selectable files for image and video media types. - * - * @param maxImageSelectable Maximum selectable count for image. - * @param maxVideoSelectable Maximum selectable count for video. - * @return {@link SelectionCreator} for fluent API. - */ - public SelectionCreator maxSelectablePerMediaType(int maxImageSelectable, int maxVideoSelectable) { - if (maxImageSelectable < 1 || maxVideoSelectable < 1) - throw new IllegalArgumentException(("max selectable must be greater than or equal to one")); - mSelectionSpec.maxSelectable = -1; - mSelectionSpec.maxImageSelectable = maxImageSelectable; - mSelectionSpec.maxVideoSelectable = maxVideoSelectable; - return this; - } - - /** - * Add filter to filter each selecting item. - * - * @param filter {@link Filter} - * @return {@link SelectionCreator} for fluent API. - */ - public SelectionCreator addFilter(@NonNull Filter filter) { - if (mSelectionSpec.filters == null) { - mSelectionSpec.filters = new ArrayList<>(); - } - if (filter == null) throw new IllegalArgumentException("filter cannot be null"); - mSelectionSpec.filters.add(filter); - return this; - } - - /** - * Determines whether the photo capturing is enabled or not on the media grid view. - *

- * If this value is set true, photo capturing entry will appear only on All Media's page. - * - * @param enable Whether to enable capturing or not. Default value is false; - * @return {@link SelectionCreator} for fluent API. - */ - public SelectionCreator capture(boolean enable) { - mSelectionSpec.capture = enable; - return this; - } - - /** - * Show a original photo check options.Let users decide whether use original photo after select - * - * @param enable Whether to enable original photo or not - * @return {@link SelectionCreator} for fluent API. - */ - public SelectionCreator originalEnable(boolean enable) { - mSelectionSpec.originalable = enable; - return this; - } - - - /** - * Determines Whether to hide top and bottom toolbar in PreView mode ,when user tap the picture - * @param enable - * @return {@link SelectionCreator} for fluent API. - */ - public SelectionCreator autoHideToolbarOnSingleTap(boolean enable) { - mSelectionSpec.autoHideToobar = enable; - return this; - } - - /** - * Maximum original size,the unit is MB. Only useful when {link@originalEnable} set true - * - * @param size Maximum original size. Default value is Integer.MAX_VALUE - * @return {@link SelectionCreator} for fluent API. - */ - public SelectionCreator maxOriginalSize(int size) { - mSelectionSpec.originalMaxSize = size; - return this; - } - - /** - * Capture strategy provided for the location to save photos including internal and external - * storage and also a authority for {@link android.support.v4.content.FileProvider}. - * - * @param captureStrategy {@link CaptureStrategy}, needed only when capturing is enabled. - * @return {@link SelectionCreator} for fluent API. - */ - public SelectionCreator captureStrategy(CaptureStrategy captureStrategy) { - mSelectionSpec.captureStrategy = captureStrategy; - return this; - } - - /** - * Set the desired orientation of this activity. - * - * @param orientation An orientation constant as used in {@link ScreenOrientation}. - * Default value is {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_PORTRAIT}. - * @return {@link SelectionCreator} for fluent API. - * @see Activity#setRequestedOrientation(int) - */ - public SelectionCreator restrictOrientation(@ScreenOrientation int orientation) { - mSelectionSpec.orientation = orientation; - return this; - } - - /** - * Set a fixed span count for the media grid. Same for different screen orientations. - *

- * This will be ignored when {@link #gridExpectedSize(int)} is set. - * - * @param spanCount Requested span count. - * @return {@link SelectionCreator} for fluent API. - */ - public SelectionCreator spanCount(int spanCount) { - if (spanCount < 1) throw new IllegalArgumentException("spanCount cannot be less than 1"); - mSelectionSpec.spanCount = spanCount; - return this; - } - - /** - * Set expected size for media grid to adapt to different screen sizes. This won't necessarily - * be applied cause the media grid should fill the view container. The measured media grid's - * size will be as close to this value as possible. - * - * @param size Expected media grid size in pixel. - * @return {@link SelectionCreator} for fluent API. - */ - public SelectionCreator gridExpectedSize(int size) { - mSelectionSpec.gridExpectedSize = size; - return this; - } - - /** - * Photo thumbnail's scale compared to the View's size. It should be a float value in (0.0, - * 1.0]. - * - * @param scale Thumbnail's scale in (0.0, 1.0]. Default value is 0.5. - * @return {@link SelectionCreator} for fluent API. - */ - public SelectionCreator thumbnailScale(float scale) { - if (scale <= 0f || scale > 1f) - throw new IllegalArgumentException("Thumbnail scale must be between (0.0, 1.0]"); - mSelectionSpec.thumbnailScale = scale; - return this; - } - - /** - * Provide an image engine. - *

- * There are two built-in image engines: - * 1. {@link com.zhihu.matisse.engine.impl.GlideEngine} - * 2. {@link com.zhihu.matisse.engine.impl.PicassoEngine} - * And you can implement your own image engine. - * - * @param imageEngine {@link ImageEngine} - * @return {@link SelectionCreator} for fluent API. - */ - public SelectionCreator imageEngine(ImageEngine imageEngine) { - mSelectionSpec.imageEngine = imageEngine; - return this; - } - - /** - * Set listener for callback immediately when user select or unselect something. - *

- * It's a redundant API with {@link Matisse#obtainResult(Intent)}, - * we only suggest you to use this API when you need to do something immediately. - * - * @param listener {@link OnSelectedListener} - * @return {@link SelectionCreator} for fluent API. - */ - @NonNull - public SelectionCreator setOnSelectedListener(@Nullable OnSelectedListener listener) { - mSelectionSpec.onSelectedListener = listener; - return this; - } - - /** - * Set listener for callback immediately when user check or uncheck original. - * - * @param listener {@link OnSelectedListener} - * @return {@link SelectionCreator} for fluent API. - */ - public SelectionCreator setOnCheckedListener(@Nullable OnCheckedListener listener) { - mSelectionSpec.onCheckedListener = listener; - return this; - } - - /** - * Start to select media and wait for result. - * - * @param requestCode Identity of the request Activity or Fragment. - */ - public void forResult(int requestCode) { - Activity activity = mMatisse.getActivity(); - if (activity == null) { - return; - } - - Intent intent = new Intent(activity, MatisseActivity.class); - - Fragment fragment = mMatisse.getFragment(); - if (fragment != null) { - fragment.startActivityForResult(intent, requestCode); - } else { - activity.startActivityForResult(intent, requestCode); - } - } - -} diff --git a/matisse/src/main/java/com/zhihu/matisse/engine/ImageEngine.java b/matisse/src/main/java/com/zhihu/matisse/engine/ImageEngine.java deleted file mode 100644 index 84e5c96..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/engine/ImageEngine.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.engine; - -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.widget.ImageView; - -/** - * Image loader interface. There are predefined {@link com.zhihu.matisse.engine.impl.GlideEngine} - * and {@link com.zhihu.matisse.engine.impl.PicassoEngine}. - */ -@SuppressWarnings("unused") -public interface ImageEngine { - - /** - * Load thumbnail of a static image resource. - * - * @param context Context - * @param resize Desired size of the origin image - * @param placeholder Placeholder drawable when image is not loaded yet - * @param imageView ImageView widget - * @param uri Uri of the loaded image - */ - void loadThumbnail(Context context, int resize, Drawable placeholder, ImageView imageView, Uri uri); - - /** - * Load thumbnail of a gif image resource. You don't have to load an animated gif when it's only - * a thumbnail tile. - * - * @param context Context - * @param resize Desired size of the origin image - * @param placeholder Placeholder drawable when image is not loaded yet - * @param imageView ImageView widget - * @param uri Uri of the loaded image - */ - void loadGifThumbnail(Context context, int resize, Drawable placeholder, ImageView imageView, Uri uri); - - /** - * Load a static image resource. - * - * @param context Context - * @param resizeX Desired x-size of the origin image - * @param resizeY Desired y-size of the origin image - * @param imageView ImageView widget - * @param uri Uri of the loaded image - */ - void loadImage(Context context, int resizeX, int resizeY, ImageView imageView, Uri uri); - - /** - * Load a gif image resource. - * - * @param context Context - * @param resizeX Desired x-size of the origin image - * @param resizeY Desired y-size of the origin image - * @param imageView ImageView widget - * @param uri Uri of the loaded image - */ - void loadGifImage(Context context, int resizeX, int resizeY, ImageView imageView, Uri uri); - - /** - * Whether this implementation supports animated gif. - * Just knowledge of it, convenient for users. - * - * @return true support animated gif, false do not support animated gif. - */ - boolean supportAnimatedGif(); -} diff --git a/matisse/src/main/java/com/zhihu/matisse/engine/impl/GlideEngine.java b/matisse/src/main/java/com/zhihu/matisse/engine/impl/GlideEngine.java deleted file mode 100644 index d1b2049..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/engine/impl/GlideEngine.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.engine.impl; - -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.widget.ImageView; - -import com.bumptech.glide.Glide; -import com.bumptech.glide.Priority; -import com.bumptech.glide.request.RequestOptions; -import com.zhihu.matisse.engine.ImageEngine; - -/** - * {@link ImageEngine} implementation using Glide. - */ - -public class GlideEngine implements ImageEngine { - - @Override - public void loadThumbnail(Context context, int resize, Drawable placeholder, ImageView imageView, Uri uri) { - /* Glide.with(context) - .load(uri) - .asBitmap() // some .jpeg files are actually gif - .placeholder(placeholder) - .override(resize, resize) - .centerCrop() - .into(imageView);*/ - RequestOptions requestOptions = new RequestOptions().centerCrop(); - Glide.with(context).asDrawable().load(uri).apply(requestOptions).into(imageView); - } - - @Override - public void loadGifThumbnail(Context context, int resize, Drawable placeholder, ImageView imageView, - Uri uri) { - - RequestOptions requestOptions = new RequestOptions().override(resize,resize).centerCrop().error(placeholder).placeholder(placeholder); - Glide.with(context).asDrawable().load(uri).apply(requestOptions).into(imageView); - /*Glide.with(context) - .load(uri) - .asBitmap() - .placeholder(placeholder) - .override(resize, resize) - .centerCrop() - .into(imageView);*/ - } - - @Override - public void loadImage(Context context, int resizeX, int resizeY, ImageView imageView, Uri uri) { - /* Glide.with(context) - .load(uri) - .override(resizeX, resizeY) - .priority(Priority.HIGH) - .fitCenter() - .into(imageView);*/ - RequestOptions requestOptions = new RequestOptions().override(resizeX,resizeY).fitCenter().priority(Priority.HIGH); - Glide.with(context).asDrawable().load(uri).apply(requestOptions).into(imageView); - } - - @Override - public void loadGifImage(Context context, int resizeX, int resizeY, ImageView imageView, Uri uri) { - /*Glide.with(context) - .load(uri) - .asGif() - .override(resizeX, resizeY) - .priority(Priority.HIGH) - .into(imageView);*/ - - RequestOptions requestOptions = new RequestOptions().override(resizeX,resizeY).priority(Priority.HIGH); - Glide.with(context).asGif().load(uri).apply(requestOptions).into(imageView); - } - - @Override - public boolean supportAnimatedGif() { - return true; - } - -} diff --git a/matisse/src/main/java/com/zhihu/matisse/engine/impl/PicassoEngine.java b/matisse/src/main/java/com/zhihu/matisse/engine/impl/PicassoEngine.java deleted file mode 100644 index 4ee33ea..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/engine/impl/PicassoEngine.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.engine.impl; - -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.widget.ImageView; - -import com.squareup.picasso.Picasso; -import com.zhihu.matisse.engine.ImageEngine; - -/** - * {@link ImageEngine} implementation using Picasso. - */ - -public class PicassoEngine implements ImageEngine { - - @Override - public void loadThumbnail(Context context, int resize, Drawable placeholder, ImageView imageView, Uri uri) { - Picasso.with(context).load(uri).placeholder(placeholder) - .resize(resize, resize) - .centerCrop() - .into(imageView); - } - - @Override - public void loadGifThumbnail(Context context, int resize, Drawable placeholder, ImageView imageView, - Uri uri) { - loadThumbnail(context, resize, placeholder, imageView, uri); - } - - @Override - public void loadImage(Context context, int resizeX, int resizeY, ImageView imageView, Uri uri) { - Picasso.with(context).load(uri).resize(resizeX, resizeY).priority(Picasso.Priority.HIGH) - .centerInside().into(imageView); - } - - @Override - public void loadGifImage(Context context, int resizeX, int resizeY, ImageView imageView, Uri uri) { - loadImage(context, resizeX, resizeY, imageView, uri); - } - - @Override - public boolean supportAnimatedGif() { - return false; - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/filter/Filter.java b/matisse/src/main/java/com/zhihu/matisse/filter/Filter.java deleted file mode 100644 index 0942364..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/filter/Filter.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.filter; - -import android.content.Context; - -import com.zhihu.matisse.MimeType; -import com.zhihu.matisse.SelectionCreator; -import com.zhihu.matisse.internal.entity.Item; -import com.zhihu.matisse.internal.entity.IncapableCause; - -import java.util.Set; - -/** - * Filter for choosing a {@link Item}. You can add multiple Filters through - * {@link SelectionCreator#addFilter(Filter)}. - */ -@SuppressWarnings("unused") -public abstract class Filter { - /** - * Convenient constant for a minimum value. - */ - public static final int MIN = 0; - /** - * Convenient constant for a maximum value. - */ - public static final int MAX = Integer.MAX_VALUE; - /** - * Convenient constant for 1024. - */ - public static final int K = 1024; - - /** - * Against what mime types this filter applies. - */ - protected abstract Set constraintTypes(); - - /** - * Invoked for filtering each item. - * - * @return null if selectable, {@link IncapableCause} if not selectable. - */ - public abstract IncapableCause filter(Context context, Item item); - - /** - * Whether an {@link Item} need filtering. - */ - protected boolean needFiltering(Context context, Item item) { - for (MimeType type : constraintTypes()) { - if (type.checkType(context.getContentResolver(), item.getContentUri())) { - return true; - } - } - return false; - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/entity/Album.java b/matisse/src/main/java/com/zhihu/matisse/internal/entity/Album.java deleted file mode 100644 index 9ebafb8..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/entity/Album.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2014 nohana, Inc. - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.entity; - -import android.content.Context; -import android.database.Cursor; -import android.os.Parcel; -import android.os.Parcelable; -import android.provider.MediaStore; -import android.support.annotation.Nullable; - -import com.zhihu.matisse.R; -import com.zhihu.matisse.internal.loader.AlbumLoader; - -public class Album implements Parcelable { - public static final Creator CREATOR = new Creator() { - @Nullable - @Override - public Album createFromParcel(Parcel source) { - return new Album(source); - } - - @Override - public Album[] newArray(int size) { - return new Album[size]; - } - }; - public static final String ALBUM_ID_ALL = String.valueOf(-1); - public static final String ALBUM_NAME_ALL = "All"; - - private final String mId; - private final String mCoverPath; - private final String mDisplayName; - private long mCount; - - Album(String id, String coverPath, String albumName, long count) { - mId = id; - mCoverPath = coverPath; - mDisplayName = albumName; - mCount = count; - } - - Album(Parcel source) { - mId = source.readString(); - mCoverPath = source.readString(); - mDisplayName = source.readString(); - mCount = source.readLong(); - } - - /** - * Constructs a new {@link Album} entity from the {@link Cursor}. - * This method is not responsible for managing cursor resource, such as close, iterate, and so on. - */ - public static Album valueOf(Cursor cursor) { - return new Album( - cursor.getString(cursor.getColumnIndex("bucket_id")), - cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DATA)), - cursor.getString(cursor.getColumnIndex("bucket_display_name")), - cursor.getLong(cursor.getColumnIndex(AlbumLoader.COLUMN_COUNT))); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mId); - dest.writeString(mCoverPath); - dest.writeString(mDisplayName); - dest.writeLong(mCount); - } - - public String getId() { - return mId; - } - - public String getCoverPath() { - return mCoverPath; - } - - public long getCount() { - return mCount; - } - - public void addCaptureCount() { - mCount++; - } - - public String getDisplayName(Context context) { - if (isAll()) { - return context.getString(R.string.album_name_all); - } - return mDisplayName; - } - - public boolean isAll() { - return ALBUM_ID_ALL.equals(mId); - } - - public boolean isEmpty() { - return mCount == 0; - } - -} \ No newline at end of file diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/entity/CaptureStrategy.java b/matisse/src/main/java/com/zhihu/matisse/internal/entity/CaptureStrategy.java deleted file mode 100644 index c4de7ca..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/entity/CaptureStrategy.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.entity; - -public class CaptureStrategy { - - public final boolean isPublic; - public final String authority; - public final String directory; - - public CaptureStrategy(boolean isPublic, String authority) { - this(isPublic, authority, null); - } - - public CaptureStrategy(boolean isPublic, String authority, String directory) { - this.isPublic = isPublic; - this.authority = authority; - this.directory = directory; - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/entity/IncapableCause.java b/matisse/src/main/java/com/zhihu/matisse/internal/entity/IncapableCause.java deleted file mode 100644 index 5c39206..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/entity/IncapableCause.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.entity; - -import android.content.Context; -import android.support.annotation.IntDef; -import android.support.v4.app.FragmentActivity; -import android.widget.Toast; - -import com.zhihu.matisse.internal.ui.widget.IncapableDialog; - -import java.lang.annotation.Retention; - -import static java.lang.annotation.RetentionPolicy.SOURCE; - -@SuppressWarnings("unused") -public class IncapableCause { - public static final int TOAST = 0x00; - public static final int DIALOG = 0x01; - public static final int NONE = 0x02; - - @Retention(SOURCE) - @IntDef({TOAST, DIALOG, NONE}) - public @interface Form { - } - - private int mForm = TOAST; - private String mTitle; - private String mMessage; - - public IncapableCause(String message) { - mMessage = message; - } - - public IncapableCause(String title, String message) { - mTitle = title; - mMessage = message; - } - - public IncapableCause(@Form int form, String message) { - mForm = form; - mMessage = message; - } - - public IncapableCause(@Form int form, String title, String message) { - mForm = form; - mTitle = title; - mMessage = message; - } - - public static void handleCause(Context context, IncapableCause cause) { - if (cause == null) - return; - - switch (cause.mForm) { - case NONE: - // do nothing. - break; - case DIALOG: - IncapableDialog incapableDialog = IncapableDialog.newInstance(cause.mTitle, cause.mMessage); - incapableDialog.show(((FragmentActivity) context).getSupportFragmentManager(), - IncapableDialog.class.getName()); - break; - case TOAST: - default: - Toast.makeText(context, cause.mMessage, Toast.LENGTH_SHORT).show(); - break; - } - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/entity/Item.java b/matisse/src/main/java/com/zhihu/matisse/internal/entity/Item.java deleted file mode 100644 index e854deb..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/entity/Item.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (C) 2014 nohana, Inc. - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.entity; - -import android.content.ContentUris; -import android.database.Cursor; -import android.net.Uri; -import android.os.Parcel; -import android.os.Parcelable; -import android.provider.MediaStore; -import android.support.annotation.Nullable; - -import com.zhihu.matisse.MimeType; - -public class Item implements Parcelable { - public static final Creator CREATOR = new Creator() { - @Override - @Nullable - public Item createFromParcel(Parcel source) { - return new Item(source); - } - - @Override - public Item[] newArray(int size) { - return new Item[size]; - } - }; - public static final long ITEM_ID_CAPTURE = -1; - public static final String ITEM_DISPLAY_NAME_CAPTURE = "Capture"; - public final long id; - public final String mimeType; - public final Uri uri; - public final long size; - public final long duration; // only for video, in ms - - private Item(long id, String mimeType, long size, long duration) { - this.id = id; - this.mimeType = mimeType; - Uri contentUri; - if (isImage()) { - contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; - } else if (isVideo()) { - contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; - } else { - // ? - contentUri = MediaStore.Files.getContentUri("external"); - } - this.uri = ContentUris.withAppendedId(contentUri, id); - this.size = size; - this.duration = duration; - } - - private Item(Parcel source) { - id = source.readLong(); - mimeType = source.readString(); - uri = source.readParcelable(Uri.class.getClassLoader()); - size = source.readLong(); - duration = source.readLong(); - } - - public static Item valueOf(Cursor cursor) { - return new Item(cursor.getLong(cursor.getColumnIndex(MediaStore.Files.FileColumns._ID)), - cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.MIME_TYPE)), - cursor.getLong(cursor.getColumnIndex(MediaStore.MediaColumns.SIZE)), - cursor.getLong(cursor.getColumnIndex("duration"))); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeLong(id); - dest.writeString(mimeType); - dest.writeParcelable(uri, 0); - dest.writeLong(size); - dest.writeLong(duration); - } - - public Uri getContentUri() { - return uri; - } - - public boolean isCapture() { - return id == ITEM_ID_CAPTURE; - } - - public boolean isImage() { - if (mimeType == null) return false; - return mimeType.equals(MimeType.JPEG.toString()) - || mimeType.equals(MimeType.PNG.toString()) - || mimeType.equals(MimeType.GIF.toString()) - || mimeType.equals(MimeType.BMP.toString()) - || mimeType.equals(MimeType.WEBP.toString()); - } - - public boolean isGif() { - if (mimeType == null) return false; - return mimeType.equals(MimeType.GIF.toString()); - } - - public boolean isVideo() { - if (mimeType == null) return false; - return mimeType.equals(MimeType.MPEG.toString()) - || mimeType.equals(MimeType.MP4.toString()) - || mimeType.equals(MimeType.QUICKTIME.toString()) - || mimeType.equals(MimeType.THREEGPP.toString()) - || mimeType.equals(MimeType.THREEGPP2.toString()) - || mimeType.equals(MimeType.MKV.toString()) - || mimeType.equals(MimeType.WEBM.toString()) - || mimeType.equals(MimeType.TS.toString()) - || mimeType.equals(MimeType.AVI.toString()); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof Item)) { - return false; - } - - Item other = (Item) obj; - return id == other.id - && (mimeType != null && mimeType.equals(other.mimeType) - || (mimeType == null && other.mimeType == null)) - && (uri != null && uri.equals(other.uri) - || (uri == null && other.uri == null)) - && size == other.size - && duration == other.duration; - } - - @Override - public int hashCode() { - int result = 1; - result = 31 * result + Long.valueOf(id).hashCode(); - if (mimeType != null) { - result = 31 * result + mimeType.hashCode(); - } - result = 31 * result + uri.hashCode(); - result = 31 * result + Long.valueOf(size).hashCode(); - result = 31 * result + Long.valueOf(duration).hashCode(); - return result; - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/entity/SelectionSpec.java b/matisse/src/main/java/com/zhihu/matisse/internal/entity/SelectionSpec.java deleted file mode 100644 index 77d28a9..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/entity/SelectionSpec.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2014 nohana, Inc. - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.entity; - -import android.content.pm.ActivityInfo; -import android.support.annotation.StyleRes; - -import com.zhihu.matisse.MimeType; -import com.zhihu.matisse.R; -import com.zhihu.matisse.engine.ImageEngine; -import com.zhihu.matisse.engine.impl.GlideEngine; -import com.zhihu.matisse.filter.Filter; -import com.zhihu.matisse.listener.OnCheckedListener; -import com.zhihu.matisse.listener.OnSelectedListener; - -import java.util.List; -import java.util.Set; - -public final class SelectionSpec { - - public Set mimeTypeSet; - public boolean mediaTypeExclusive; - public boolean showSingleMediaType; - @StyleRes - public int themeId; - public int orientation; - public boolean countable; - public int maxSelectable; - public int maxImageSelectable; - public int maxVideoSelectable; - public List filters; - public boolean capture; - public CaptureStrategy captureStrategy; - public int spanCount; - public int gridExpectedSize; - public float thumbnailScale; - public ImageEngine imageEngine; - public boolean hasInited; - public OnSelectedListener onSelectedListener; - public boolean originalable; - public boolean autoHideToobar; - public int originalMaxSize; - public OnCheckedListener onCheckedListener; - - private SelectionSpec() { - } - - public static SelectionSpec getInstance() { - return InstanceHolder.INSTANCE; - } - - public static SelectionSpec getCleanInstance() { - SelectionSpec selectionSpec = getInstance(); - selectionSpec.reset(); - return selectionSpec; - } - - private void reset() { - mimeTypeSet = null; - mediaTypeExclusive = true; - showSingleMediaType = false; - themeId = R.style.Matisse_Zhihu; - orientation = 0; - countable = false; - maxSelectable = 1; - maxImageSelectable = 0; - maxVideoSelectable = 0; - filters = null; - capture = false; - captureStrategy = null; - spanCount = 3; - gridExpectedSize = 0; - thumbnailScale = 0.5f; - imageEngine = new GlideEngine(); - hasInited = true; - originalable = false; - autoHideToobar = false; - originalMaxSize = Integer.MAX_VALUE; - } - - public boolean singleSelectionModeEnabled() { - return !countable && (maxSelectable == 1 || (maxImageSelectable == 1 && maxVideoSelectable == 1)); - } - - public boolean needOrientationRestriction() { - return orientation != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; - } - - public boolean onlyShowImages() { - return showSingleMediaType && MimeType.ofImage().containsAll(mimeTypeSet); - } - - public boolean onlyShowVideos() { - return showSingleMediaType && MimeType.ofVideo().containsAll(mimeTypeSet); - } - - private static final class InstanceHolder { - private static final SelectionSpec INSTANCE = new SelectionSpec(); - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/loader/AlbumLoader.java b/matisse/src/main/java/com/zhihu/matisse/internal/loader/AlbumLoader.java deleted file mode 100644 index f328296..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/loader/AlbumLoader.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2014 nohana, Inc. - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.loader; - -import android.content.Context; -import android.database.Cursor; -import android.database.MatrixCursor; -import android.database.MergeCursor; -import android.net.Uri; -import android.provider.MediaStore; -import android.support.v4.content.CursorLoader; - -import com.zhihu.matisse.internal.entity.Album; -import com.zhihu.matisse.internal.entity.SelectionSpec; - -/** - * Load all albums (grouped by bucket_id) into a single cursor. - */ -public class AlbumLoader extends CursorLoader { - public static final String COLUMN_COUNT = "count"; - private static final Uri QUERY_URI = MediaStore.Files.getContentUri("external"); - private static final String[] COLUMNS = { - MediaStore.Files.FileColumns._ID, - "bucket_id", - "bucket_display_name", - MediaStore.MediaColumns.DATA, - COLUMN_COUNT}; - private static final String[] PROJECTION = { - MediaStore.Files.FileColumns._ID, - "bucket_id", - "bucket_display_name", - MediaStore.MediaColumns.DATA, - "COUNT(*) AS " + COLUMN_COUNT}; - - // === params for showSingleMediaType: false === - private static final String SELECTION = - "(" + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?" - + " OR " - + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?)" - + " AND " + MediaStore.MediaColumns.SIZE + ">0" - + ") GROUP BY (bucket_id"; - private static final String[] SELECTION_ARGS = { - String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE), - String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO), - }; - // ============================================= - - // === params for showSingleMediaType: true === - private static final String SELECTION_FOR_SINGLE_MEDIA_TYPE = - MediaStore.Files.FileColumns.MEDIA_TYPE + "=?" - + " AND " + MediaStore.MediaColumns.SIZE + ">0" - + ") GROUP BY (bucket_id"; - - private static String[] getSelectionArgsForSingleMediaType(int mediaType) { - return new String[]{String.valueOf(mediaType)}; - } - // ============================================= - - private static final String BUCKET_ORDER_BY = "datetaken DESC"; - - private AlbumLoader(Context context, String selection, String[] selectionArgs) { - super(context, QUERY_URI, PROJECTION, selection, selectionArgs, BUCKET_ORDER_BY); - } - - public static CursorLoader newInstance(Context context) { - String selection; - String[] selectionArgs; - if (SelectionSpec.getInstance().onlyShowImages()) { - selection = SELECTION_FOR_SINGLE_MEDIA_TYPE; - selectionArgs = getSelectionArgsForSingleMediaType(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE); - } else if (SelectionSpec.getInstance().onlyShowVideos()) { - selection = SELECTION_FOR_SINGLE_MEDIA_TYPE; - selectionArgs = getSelectionArgsForSingleMediaType(MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO); - } else { - selection = SELECTION; - selectionArgs = SELECTION_ARGS; - } - return new AlbumLoader(context, selection, selectionArgs); - } - - @Override - public Cursor loadInBackground() { - Cursor albums = super.loadInBackground(); - MatrixCursor allAlbum = new MatrixCursor(COLUMNS); - int totalCount = 0; - String allAlbumCoverPath = ""; - if (albums != null) { - while (albums.moveToNext()) { - totalCount += albums.getInt(albums.getColumnIndex(COLUMN_COUNT)); - } - if (albums.moveToFirst()) { - allAlbumCoverPath = albums.getString(albums.getColumnIndex(MediaStore.MediaColumns.DATA)); - } - } - allAlbum.addRow(new String[]{Album.ALBUM_ID_ALL, Album.ALBUM_ID_ALL, Album.ALBUM_NAME_ALL, allAlbumCoverPath, - String.valueOf(totalCount)}); - - return new MergeCursor(new Cursor[]{allAlbum, albums}); - } - - @Override - public void onContentChanged() { - // FIXME a dirty way to fix loading multiple times - } -} \ No newline at end of file diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/loader/AlbumMediaLoader.java b/matisse/src/main/java/com/zhihu/matisse/internal/loader/AlbumMediaLoader.java deleted file mode 100644 index ea2b291..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/loader/AlbumMediaLoader.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (C) 2014 nohana, Inc. - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.loader; - -import android.content.Context; -import android.database.Cursor; -import android.database.MatrixCursor; -import android.database.MergeCursor; -import android.net.Uri; -import android.provider.MediaStore; -import android.support.v4.content.CursorLoader; - -import com.zhihu.matisse.internal.entity.Album; -import com.zhihu.matisse.internal.entity.Item; -import com.zhihu.matisse.internal.entity.SelectionSpec; -import com.zhihu.matisse.internal.utils.MediaStoreCompat; - -/** - * Load images and videos into a single cursor. - */ -public class AlbumMediaLoader extends CursorLoader { - private static final Uri QUERY_URI = MediaStore.Files.getContentUri("external"); - private static final String[] PROJECTION = { - MediaStore.Files.FileColumns._ID, - MediaStore.MediaColumns.DISPLAY_NAME, - MediaStore.MediaColumns.MIME_TYPE, - MediaStore.MediaColumns.SIZE, - "duration"}; - - // === params for album ALL && showSingleMediaType: false === - private static final String SELECTION_ALL = - "(" + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?" - + " OR " - + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?)" - + " AND " + MediaStore.MediaColumns.SIZE + ">0"; - private static final String[] SELECTION_ALL_ARGS = { - String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE), - String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO), - }; - // =========================================================== - - // === params for album ALL && showSingleMediaType: true === - private static final String SELECTION_ALL_FOR_SINGLE_MEDIA_TYPE = - MediaStore.Files.FileColumns.MEDIA_TYPE + "=?" - + " AND " + MediaStore.MediaColumns.SIZE + ">0"; - - private static String[] getSelectionArgsForSingleMediaType(int mediaType) { - return new String[]{String.valueOf(mediaType)}; - } - // ========================================================= - - // === params for ordinary album && showSingleMediaType: false === - private static final String SELECTION_ALBUM = - "(" + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?" - + " OR " - + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?)" - + " AND " - + " bucket_id=?" - + " AND " + MediaStore.MediaColumns.SIZE + ">0"; - - private static String[] getSelectionAlbumArgs(String albumId) { - return new String[]{ - String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE), - String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO), - albumId - }; - } - // =============================================================== - - // === params for ordinary album && showSingleMediaType: true === - private static final String SELECTION_ALBUM_FOR_SINGLE_MEDIA_TYPE = - MediaStore.Files.FileColumns.MEDIA_TYPE + "=?" - + " AND " - + " bucket_id=?" - + " AND " + MediaStore.MediaColumns.SIZE + ">0"; - - private static String[] getSelectionAlbumArgsForSingleMediaType(int mediaType, String albumId) { - return new String[]{String.valueOf(mediaType), albumId}; - } - // =============================================================== - - private static final String ORDER_BY = MediaStore.Images.Media.DATE_TAKEN + " DESC"; - private final boolean mEnableCapture; - - private AlbumMediaLoader(Context context, String selection, String[] selectionArgs, boolean capture) { - super(context, QUERY_URI, PROJECTION, selection, selectionArgs, ORDER_BY); - mEnableCapture = capture; - } - - public static CursorLoader newInstance(Context context, Album album, boolean capture) { - String selection; - String[] selectionArgs; - boolean enableCapture; - - if (album.isAll()) { - if (SelectionSpec.getInstance().onlyShowImages()) { - selection = SELECTION_ALL_FOR_SINGLE_MEDIA_TYPE; - selectionArgs = getSelectionArgsForSingleMediaType(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE); - } else if (SelectionSpec.getInstance().onlyShowVideos()) { - selection = SELECTION_ALL_FOR_SINGLE_MEDIA_TYPE; - selectionArgs = getSelectionArgsForSingleMediaType(MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO); - } else { - selection = SELECTION_ALL; - selectionArgs = SELECTION_ALL_ARGS; - } - enableCapture = capture; - } else { - if (SelectionSpec.getInstance().onlyShowImages()) { - selection = SELECTION_ALBUM_FOR_SINGLE_MEDIA_TYPE; - selectionArgs = getSelectionAlbumArgsForSingleMediaType(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE, - album.getId()); - } else if (SelectionSpec.getInstance().onlyShowVideos()) { - selection = SELECTION_ALBUM_FOR_SINGLE_MEDIA_TYPE; - selectionArgs = getSelectionAlbumArgsForSingleMediaType(MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO, - album.getId()); - } else { - selection = SELECTION_ALBUM; - selectionArgs = getSelectionAlbumArgs(album.getId()); - } - enableCapture = false; - } - return new AlbumMediaLoader(context, selection, selectionArgs, enableCapture); - } - - @Override - public Cursor loadInBackground() { - Cursor result = super.loadInBackground(); - if (!mEnableCapture || !MediaStoreCompat.hasCameraFeature(getContext())) { - return result; - } - MatrixCursor dummy = new MatrixCursor(PROJECTION); - dummy.addRow(new Object[]{Item.ITEM_ID_CAPTURE, Item.ITEM_DISPLAY_NAME_CAPTURE, "", 0, 0}); - return new MergeCursor(new Cursor[]{dummy, result}); - } - - @Override - public void onContentChanged() { - // FIXME a dirty way to fix loading multiple times - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/model/AlbumCollection.java b/matisse/src/main/java/com/zhihu/matisse/internal/model/AlbumCollection.java deleted file mode 100644 index bdfa925..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/model/AlbumCollection.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2014 nohana, Inc. - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.model; - -import android.content.Context; -import android.database.Cursor; -import android.os.Bundle; -import android.support.v4.app.FragmentActivity; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.Loader; - -import com.zhihu.matisse.internal.loader.AlbumLoader; - -import java.lang.ref.WeakReference; - -public class AlbumCollection implements LoaderManager.LoaderCallbacks { - private static final int LOADER_ID = 1; - private static final String STATE_CURRENT_SELECTION = "state_current_selection"; - private WeakReference mContext; - private LoaderManager mLoaderManager; - private AlbumCallbacks mCallbacks; - private int mCurrentSelection; - private boolean mLoadFinished; - - @Override - public Loader onCreateLoader(int id, Bundle args) { - Context context = mContext.get(); - if (context == null) { - return null; - } - mLoadFinished = false; - return AlbumLoader.newInstance(context); - } - - @Override - public void onLoadFinished(Loader loader, Cursor data) { - Context context = mContext.get(); - if (context == null) { - return; - } - - if (!mLoadFinished) { - mLoadFinished = true; - mCallbacks.onAlbumLoad(data); - } - } - - @Override - public void onLoaderReset(Loader loader) { - Context context = mContext.get(); - if (context == null) { - return; - } - - mCallbacks.onAlbumReset(); - } - - public void onCreate(FragmentActivity activity, AlbumCallbacks callbacks) { - mContext = new WeakReference(activity); - mLoaderManager = activity.getSupportLoaderManager(); - mCallbacks = callbacks; - } - - public void onRestoreInstanceState(Bundle savedInstanceState) { - if (savedInstanceState == null) { - return; - } - - mCurrentSelection = savedInstanceState.getInt(STATE_CURRENT_SELECTION); - } - - public void onSaveInstanceState(Bundle outState) { - outState.putInt(STATE_CURRENT_SELECTION, mCurrentSelection); - } - - public void onDestroy() { - if (mLoaderManager != null) { - mLoaderManager.destroyLoader(LOADER_ID); - } - mCallbacks = null; - } - - public void loadAlbums() { - mLoaderManager.initLoader(LOADER_ID, null, this); - } - - public int getCurrentSelection() { - return mCurrentSelection; - } - - public void setStateCurrentSelection(int currentSelection) { - mCurrentSelection = currentSelection; - } - - public interface AlbumCallbacks { - void onAlbumLoad(Cursor cursor); - - void onAlbumReset(); - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/model/AlbumMediaCollection.java b/matisse/src/main/java/com/zhihu/matisse/internal/model/AlbumMediaCollection.java deleted file mode 100644 index 90a938a..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/model/AlbumMediaCollection.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2014 nohana, Inc. - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.model; - -import android.content.Context; -import android.database.Cursor; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v4.app.FragmentActivity; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.Loader; - -import com.zhihu.matisse.internal.entity.Album; -import com.zhihu.matisse.internal.loader.AlbumMediaLoader; - -import java.lang.ref.WeakReference; - -public class AlbumMediaCollection implements LoaderManager.LoaderCallbacks { - private static final int LOADER_ID = 2; - private static final String ARGS_ALBUM = "args_album"; - private static final String ARGS_ENABLE_CAPTURE = "args_enable_capture"; - private WeakReference mContext; - private LoaderManager mLoaderManager; - private AlbumMediaCallbacks mCallbacks; - - @Override - public Loader onCreateLoader(int id, Bundle args) { - Context context = mContext.get(); - if (context == null) { - return null; - } - - Album album = args.getParcelable(ARGS_ALBUM); - if (album == null) { - return null; - } - - return AlbumMediaLoader.newInstance(context, album, - album.isAll() && args.getBoolean(ARGS_ENABLE_CAPTURE, false)); - } - - @Override - public void onLoadFinished(Loader loader, Cursor data) { - Context context = mContext.get(); - if (context == null) { - return; - } - - mCallbacks.onAlbumMediaLoad(data); - } - - @Override - public void onLoaderReset(Loader loader) { - Context context = mContext.get(); - if (context == null) { - return; - } - - mCallbacks.onAlbumMediaReset(); - } - - public void onCreate(@NonNull FragmentActivity context, @NonNull AlbumMediaCallbacks callbacks) { - mContext = new WeakReference(context); - mLoaderManager = context.getSupportLoaderManager(); - mCallbacks = callbacks; - } - - public void onDestroy() { - if (mLoaderManager != null) { - mLoaderManager.destroyLoader(LOADER_ID); - } - mCallbacks = null; - } - - public void load(@Nullable Album target) { - load(target, false); - } - - public void load(@Nullable Album target, boolean enableCapture) { - Bundle args = new Bundle(); - args.putParcelable(ARGS_ALBUM, target); - args.putBoolean(ARGS_ENABLE_CAPTURE, enableCapture); - mLoaderManager.initLoader(LOADER_ID, args, this); - } - - public interface AlbumMediaCallbacks { - - void onAlbumMediaLoad(Cursor cursor); - - void onAlbumMediaReset(); - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/model/SelectedItemCollection.java b/matisse/src/main/java/com/zhihu/matisse/internal/model/SelectedItemCollection.java deleted file mode 100644 index 7fdf690..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/model/SelectedItemCollection.java +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.model; - -import android.content.Context; -import android.content.res.Resources; -import android.net.Uri; -import android.os.Bundle; - -import com.zhihu.matisse.R; -import com.zhihu.matisse.internal.entity.IncapableCause; -import com.zhihu.matisse.internal.entity.Item; -import com.zhihu.matisse.internal.entity.SelectionSpec; -import com.zhihu.matisse.internal.ui.widget.CheckView; -import com.zhihu.matisse.internal.utils.PathUtils; -import com.zhihu.matisse.internal.utils.PhotoMetadataUtils; - -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; - -@SuppressWarnings("unused") -public class SelectedItemCollection { - - public static final String STATE_SELECTION = "state_selection"; - public static final String STATE_COLLECTION_TYPE = "state_collection_type"; - /** - * Empty collection - */ - public static final int COLLECTION_UNDEFINED = 0x00; - /** - * Collection only with images - */ - public static final int COLLECTION_IMAGE = 0x01; - /** - * Collection only with videos - */ - public static final int COLLECTION_VIDEO = 0x01 << 1; - /** - * Collection with images and videos. - */ - public static final int COLLECTION_MIXED = COLLECTION_IMAGE | COLLECTION_VIDEO; - private final Context mContext; - private Set mItems; - private int mCollectionType = COLLECTION_UNDEFINED; - - public SelectedItemCollection(Context context) { - mContext = context; - } - - public void onCreate(Bundle bundle) { - if (bundle == null) { - mItems = new LinkedHashSet<>(); - } else { - List saved = bundle.getParcelableArrayList(STATE_SELECTION); - mItems = new LinkedHashSet<>(saved); - mCollectionType = bundle.getInt(STATE_COLLECTION_TYPE, COLLECTION_UNDEFINED); - } - } - - public void setDefaultSelection(List uris) { - mItems.addAll(uris); - } - - public void onSaveInstanceState(Bundle outState) { - outState.putParcelableArrayList(STATE_SELECTION, new ArrayList<>(mItems)); - outState.putInt(STATE_COLLECTION_TYPE, mCollectionType); - } - - public Bundle getDataWithBundle() { - Bundle bundle = new Bundle(); - bundle.putParcelableArrayList(STATE_SELECTION, new ArrayList<>(mItems)); - bundle.putInt(STATE_COLLECTION_TYPE, mCollectionType); - return bundle; - } - - public boolean add(Item item) { - if (typeConflict(item)) { - throw new IllegalArgumentException("Can't select images and videos at the same time."); - } - boolean added = mItems.add(item); - if (added) { - if (mCollectionType == COLLECTION_UNDEFINED) { - if (item.isImage()) { - mCollectionType = COLLECTION_IMAGE; - } else if (item.isVideo()) { - mCollectionType = COLLECTION_VIDEO; - } - } else if (mCollectionType == COLLECTION_IMAGE) { - if (item.isVideo()) { - mCollectionType = COLLECTION_MIXED; - } - } else if (mCollectionType == COLLECTION_VIDEO) { - if (item.isImage()) { - mCollectionType = COLLECTION_MIXED; - } - } - } - return added; - } - - public boolean remove(Item item) { - boolean removed = mItems.remove(item); - if (removed) { - if (mItems.size() == 0) { - mCollectionType = COLLECTION_UNDEFINED; - } else { - if (mCollectionType == COLLECTION_MIXED) { - refineCollectionType(); - } - } - } - return removed; - } - - public void overwrite(ArrayList items, int collectionType) { - if (items.size() == 0) { - mCollectionType = COLLECTION_UNDEFINED; - } else { - mCollectionType = collectionType; - } - mItems.clear(); - mItems.addAll(items); - } - - - public List asList() { - return new ArrayList<>(mItems); - } - - public List asListOfUri() { - List uris = new ArrayList<>(); - for (Item item : mItems) { - uris.add(item.getContentUri()); - } - return uris; - } - - public List asListOfString() { - List paths = new ArrayList<>(); - for (Item item : mItems) { - paths.add(PathUtils.getPath(mContext, item.getContentUri())); - } - return paths; - } - - public boolean isEmpty() { - return mItems == null || mItems.isEmpty(); - } - - public boolean isSelected(Item item) { - return mItems.contains(item); - } - - public IncapableCause isAcceptable(Item item) { - if (maxSelectableReached()) { - int maxSelectable = currentMaxSelectable(); - String cause; - - try { - cause = mContext.getResources().getQuantityString( - R.plurals.error_over_count, - maxSelectable, - maxSelectable - ); - } catch (Resources.NotFoundException e) { - cause = mContext.getString( - R.string.error_over_count, - maxSelectable - ); - } catch (NoClassDefFoundError e) { - cause = mContext.getString( - R.string.error_over_count, - maxSelectable - ); - } - - return new IncapableCause(cause); - } else if (typeConflict(item)) { - return new IncapableCause(mContext.getString(R.string.error_type_conflict)); - } - - return PhotoMetadataUtils.isAcceptable(mContext, item); - } - - public boolean maxSelectableReached() { - return mItems.size() == currentMaxSelectable(); - } - - // depends - private int currentMaxSelectable() { - SelectionSpec spec = SelectionSpec.getInstance(); - if (spec.maxSelectable > 0) { - return spec.maxSelectable; - } else if (mCollectionType == COLLECTION_IMAGE) { - return spec.maxImageSelectable; - } else if (mCollectionType == COLLECTION_VIDEO) { - return spec.maxVideoSelectable; - } else { - return spec.maxSelectable; - } - } - - public int getCollectionType() { - return mCollectionType; - } - - private void refineCollectionType() { - boolean hasImage = false; - boolean hasVideo = false; - for (Item i : mItems) { - if (i.isImage() && !hasImage) hasImage = true; - if (i.isVideo() && !hasVideo) hasVideo = true; - } - if (hasImage && hasVideo) { - mCollectionType = COLLECTION_MIXED; - } else if (hasImage) { - mCollectionType = COLLECTION_IMAGE; - } else if (hasVideo) { - mCollectionType = COLLECTION_VIDEO; - } - } - - /** - * Determine whether there will be conflict media types. A user can only select images and videos at the same time - * while {@link SelectionSpec#mediaTypeExclusive} is set to false. - */ - public boolean typeConflict(Item item) { - return SelectionSpec.getInstance().mediaTypeExclusive - && ((item.isImage() && (mCollectionType == COLLECTION_VIDEO || mCollectionType == COLLECTION_MIXED)) - || (item.isVideo() && (mCollectionType == COLLECTION_IMAGE || mCollectionType == COLLECTION_MIXED))); - } - - public int count() { - return mItems.size(); - } - - public int checkedNumOf(Item item) { - int index = new ArrayList<>(mItems).indexOf(item); - return index == -1 ? CheckView.UNCHECKED : index + 1; - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/AlbumPreviewActivity.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/AlbumPreviewActivity.java deleted file mode 100644 index 73ff53e..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/AlbumPreviewActivity.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui; - -import android.database.Cursor; -import android.os.Bundle; -import android.support.annotation.Nullable; - -import com.zhihu.matisse.internal.entity.Album; -import com.zhihu.matisse.internal.entity.Item; -import com.zhihu.matisse.internal.entity.SelectionSpec; -import com.zhihu.matisse.internal.model.AlbumMediaCollection; -import com.zhihu.matisse.internal.ui.adapter.PreviewPagerAdapter; - -import java.util.ArrayList; -import java.util.List; - -public class AlbumPreviewActivity extends BasePreviewActivity implements - AlbumMediaCollection.AlbumMediaCallbacks { - - public static final String EXTRA_ALBUM = "extra_album"; - public static final String EXTRA_ITEM = "extra_item"; - - private AlbumMediaCollection mCollection = new AlbumMediaCollection(); - - private boolean mIsAlreadySetPosition; - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (!SelectionSpec.getInstance().hasInited) { - setResult(RESULT_CANCELED); - finish(); - return; - } - mCollection.onCreate(this, this); - Album album = getIntent().getParcelableExtra(EXTRA_ALBUM); - mCollection.load(album); - - Item item = getIntent().getParcelableExtra(EXTRA_ITEM); - if (mSpec.countable) { - mCheckView.setCheckedNum(mSelectedCollection.checkedNumOf(item)); - } else { - mCheckView.setChecked(mSelectedCollection.isSelected(item)); - } - updateSize(item); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - mCollection.onDestroy(); - } - - @Override - public void onAlbumMediaLoad(Cursor cursor) { - List items = new ArrayList<>(); - while (cursor.moveToNext()) { - items.add(Item.valueOf(cursor)); - } -// cursor.close(); - - if (items.isEmpty()) { - return; - } - - PreviewPagerAdapter adapter = (PreviewPagerAdapter) mPager.getAdapter(); - adapter.addAll(items); - adapter.notifyDataSetChanged(); - if (!mIsAlreadySetPosition) { - //onAlbumMediaLoad is called many times.. - mIsAlreadySetPosition = true; - Item selected = getIntent().getParcelableExtra(EXTRA_ITEM); - int selectedIndex = items.indexOf(selected); - mPager.setCurrentItem(selectedIndex, false); - mPreviousPos = selectedIndex; - } - } - - @Override - public void onAlbumMediaReset() { - - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/BasePreviewActivity.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/BasePreviewActivity.java deleted file mode 100644 index 82383fd..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/BasePreviewActivity.java +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui; - -import android.app.Activity; -import android.content.Intent; -import android.graphics.Color; -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.view.ViewPager; -import android.support.v4.view.animation.FastOutSlowInInterpolator; -import android.support.v7.app.AppCompatActivity; -import android.view.View; -import android.view.WindowManager; -import android.widget.FrameLayout; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.zhihu.matisse.R; -import com.zhihu.matisse.internal.entity.IncapableCause; -import com.zhihu.matisse.internal.entity.Item; -import com.zhihu.matisse.internal.entity.SelectionSpec; -import com.zhihu.matisse.internal.model.SelectedItemCollection; -import com.zhihu.matisse.internal.ui.adapter.PreviewPagerAdapter; -import com.zhihu.matisse.internal.ui.widget.CheckRadioView; -import com.zhihu.matisse.internal.ui.widget.CheckView; -import com.zhihu.matisse.internal.ui.widget.IncapableDialog; -import com.zhihu.matisse.internal.utils.PhotoMetadataUtils; -import com.zhihu.matisse.internal.utils.Platform; -import com.zhihu.matisse.listener.OnFragmentInteractionListener; - -public abstract class BasePreviewActivity extends AppCompatActivity implements View.OnClickListener, - ViewPager.OnPageChangeListener, OnFragmentInteractionListener { - - public static final String EXTRA_DEFAULT_BUNDLE = "extra_default_bundle"; - public static final String EXTRA_RESULT_BUNDLE = "extra_result_bundle"; - public static final String EXTRA_RESULT_APPLY = "extra_result_apply"; - public static final String EXTRA_RESULT_ORIGINAL_ENABLE = "extra_result_original_enable"; - public static final String CHECK_STATE = "checkState"; - - protected final SelectedItemCollection mSelectedCollection = new SelectedItemCollection(this); - protected SelectionSpec mSpec; - protected ViewPager mPager; - - protected PreviewPagerAdapter mAdapter; - - protected CheckView mCheckView; - protected TextView mButtonBack; - protected TextView mButtonApply; - protected TextView mSize; - - protected int mPreviousPos = -1; - - private LinearLayout mOriginalLayout; - private CheckRadioView mOriginal; - protected boolean mOriginalEnable; - - private FrameLayout mBottomToolbar; - private FrameLayout mTopToolbar; - private boolean mIsToolbarHide = false; - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - setTheme(SelectionSpec.getInstance().themeId); - super.onCreate(savedInstanceState); - if (!SelectionSpec.getInstance().hasInited) { - setResult(RESULT_CANCELED); - finish(); - return; - } - setContentView(R.layout.activity_media_preview); - if (Platform.hasKitKat()) { - getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); - } - - mSpec = SelectionSpec.getInstance(); - if (mSpec.needOrientationRestriction()) { - setRequestedOrientation(mSpec.orientation); - } - - if (savedInstanceState == null) { - mSelectedCollection.onCreate(getIntent().getBundleExtra(EXTRA_DEFAULT_BUNDLE)); - mOriginalEnable = getIntent().getBooleanExtra(EXTRA_RESULT_ORIGINAL_ENABLE, false); - } else { - mSelectedCollection.onCreate(savedInstanceState); - mOriginalEnable = savedInstanceState.getBoolean(CHECK_STATE); - } - mButtonBack = (TextView) findViewById(R.id.button_back); - mButtonApply = (TextView) findViewById(R.id.button_apply); - mSize = (TextView) findViewById(R.id.size); - mButtonBack.setOnClickListener(this); - mButtonApply.setOnClickListener(this); - - mPager = (ViewPager) findViewById(R.id.pager); - mPager.addOnPageChangeListener(this); - mAdapter = new PreviewPagerAdapter(getSupportFragmentManager(), null); - mPager.setAdapter(mAdapter); - mCheckView = (CheckView) findViewById(R.id.check_view); - mCheckView.setCountable(mSpec.countable); - mBottomToolbar = findViewById(R.id.bottom_toolbar); - mTopToolbar = findViewById(R.id.top_toolbar); - - mCheckView.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - Item item = mAdapter.getMediaItem(mPager.getCurrentItem()); - if (mSelectedCollection.isSelected(item)) { - mSelectedCollection.remove(item); - if (mSpec.countable) { - mCheckView.setCheckedNum(CheckView.UNCHECKED); - } else { - mCheckView.setChecked(false); - } - } else { - if (assertAddSelection(item)) { - mSelectedCollection.add(item); - if (mSpec.countable) { - mCheckView.setCheckedNum(mSelectedCollection.checkedNumOf(item)); - } else { - mCheckView.setChecked(true); - } - } - } - updateApplyButton(); - - if (mSpec.onSelectedListener != null) { - mSpec.onSelectedListener.onSelected( - mSelectedCollection.asListOfUri(), mSelectedCollection.asListOfString()); - } - } - }); - - - mOriginalLayout = findViewById(R.id.originalLayout); - mOriginal = findViewById(R.id.original); - mOriginalLayout.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - - int count = countOverMaxSize(); - if (count > 0) { - IncapableDialog incapableDialog = IncapableDialog.newInstance("", - getString(R.string.error_over_original_count, count, mSpec.originalMaxSize)); - incapableDialog.show(getSupportFragmentManager(), - IncapableDialog.class.getName()); - return; - } - - mOriginalEnable = !mOriginalEnable; - mOriginal.setChecked(mOriginalEnable); - if (!mOriginalEnable) { - mOriginal.setColor(Color.WHITE); - } - - - if (mSpec.onCheckedListener != null) { - mSpec.onCheckedListener.onCheck(mOriginalEnable); - } - } - }); - - updateApplyButton(); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - mSelectedCollection.onSaveInstanceState(outState); - outState.putBoolean("checkState", mOriginalEnable); - super.onSaveInstanceState(outState); - } - - @Override - public void onBackPressed() { - sendBackResult(false); - super.onBackPressed(); - } - - @Override - public void onClick(View v) { - if (v.getId() == R.id.button_back) { - onBackPressed(); - } else if (v.getId() == R.id.button_apply) { - sendBackResult(true); - finish(); - } - } - - @Override - public void onClick() { - if (!mSpec.autoHideToobar) { - return; - } - - if (mIsToolbarHide) { - mTopToolbar.animate() - .setInterpolator(new FastOutSlowInInterpolator()) - .translationYBy(mTopToolbar.getMeasuredHeight()) - .start(); - mBottomToolbar.animate() - .translationYBy(-mBottomToolbar.getMeasuredHeight()) - .setInterpolator(new FastOutSlowInInterpolator()) - .start(); - } else { - mTopToolbar.animate() - .setInterpolator(new FastOutSlowInInterpolator()) - .translationYBy(-mTopToolbar.getMeasuredHeight()) - .start(); - mBottomToolbar.animate() - .setInterpolator(new FastOutSlowInInterpolator()) - .translationYBy(mBottomToolbar.getMeasuredHeight()) - .start(); - } - - mIsToolbarHide = !mIsToolbarHide; - - } - - @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - - } - - @Override - public void onPageSelected(int position) { - PreviewPagerAdapter adapter = (PreviewPagerAdapter) mPager.getAdapter(); - if (mPreviousPos != -1 && mPreviousPos != position) { - ((PreviewItemFragment) adapter.instantiateItem(mPager, mPreviousPos)).resetView(); - - Item item = adapter.getMediaItem(position); - if (mSpec.countable) { - int checkedNum = mSelectedCollection.checkedNumOf(item); - mCheckView.setCheckedNum(checkedNum); - if (checkedNum > 0) { - mCheckView.setEnabled(true); - } else { - mCheckView.setEnabled(!mSelectedCollection.maxSelectableReached()); - } - } else { - boolean checked = mSelectedCollection.isSelected(item); - mCheckView.setChecked(checked); - if (checked) { - mCheckView.setEnabled(true); - } else { - mCheckView.setEnabled(!mSelectedCollection.maxSelectableReached()); - } - } - updateSize(item); - } - mPreviousPos = position; - } - - @Override - public void onPageScrollStateChanged(int state) { - - } - - private void updateApplyButton() { - int selectedCount = mSelectedCollection.count(); - if (selectedCount == 0) { - mButtonApply.setText(R.string.button_sure_default); - mButtonApply.setEnabled(false); - } else if (selectedCount == 1 && mSpec.singleSelectionModeEnabled()) { - mButtonApply.setText(R.string.button_sure_default); - mButtonApply.setEnabled(true); - } else { - mButtonApply.setEnabled(true); - mButtonApply.setText(getString(R.string.button_sure, selectedCount)); - } - - if (mSpec.originalable) { - mOriginalLayout.setVisibility(View.VISIBLE); - updateOriginalState(); - } else { - mOriginalLayout.setVisibility(View.GONE); - } - } - - - private void updateOriginalState() { - mOriginal.setChecked(mOriginalEnable); - if (!mOriginalEnable) { - mOriginal.setColor(Color.WHITE); - } - - if (countOverMaxSize() > 0) { - - if (mOriginalEnable) { - IncapableDialog incapableDialog = IncapableDialog.newInstance("", - getString(R.string.error_over_original_size, mSpec.originalMaxSize)); - incapableDialog.show(getSupportFragmentManager(), - IncapableDialog.class.getName()); - - mOriginal.setChecked(false); - mOriginal.setColor(Color.WHITE); - mOriginalEnable = false; - } - } - } - - - private int countOverMaxSize() { - int count = 0; - int selectedCount = mSelectedCollection.count(); - for (int i = 0; i < selectedCount; i++) { - Item item = mSelectedCollection.asList().get(i); - if (item.isImage()) { - float size = PhotoMetadataUtils.getSizeInMB(item.size); - if (size > mSpec.originalMaxSize) { - count++; - } - } - } - return count; - } - - protected void updateSize(Item item) { - if (item.isGif()) { - mSize.setVisibility(View.VISIBLE); - mSize.setText(PhotoMetadataUtils.getSizeInMB(item.size) + "M"); - } else { - mSize.setVisibility(View.GONE); - } - - if (item.isVideo()) { - mOriginalLayout.setVisibility(View.GONE); - } else if (mSpec.originalable) { - mOriginalLayout.setVisibility(View.VISIBLE); - } - } - - protected void sendBackResult(boolean apply) { - Intent intent = new Intent(); - intent.putExtra(EXTRA_RESULT_BUNDLE, mSelectedCollection.getDataWithBundle()); - intent.putExtra(EXTRA_RESULT_APPLY, apply); - intent.putExtra(EXTRA_RESULT_ORIGINAL_ENABLE, mOriginalEnable); - setResult(Activity.RESULT_OK, intent); - } - - private boolean assertAddSelection(Item item) { - IncapableCause cause = mSelectedCollection.isAcceptable(item); - IncapableCause.handleCause(this, cause); - return cause == null; - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/MediaSelectionFragment.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/MediaSelectionFragment.java deleted file mode 100644 index b00f09c..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/MediaSelectionFragment.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui; - -import android.content.Context; -import android.database.Cursor; -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; -import android.support.v7.widget.GridLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import com.zhihu.matisse.R; -import com.zhihu.matisse.internal.entity.Album; -import com.zhihu.matisse.internal.entity.Item; -import com.zhihu.matisse.internal.entity.SelectionSpec; -import com.zhihu.matisse.internal.model.AlbumMediaCollection; -import com.zhihu.matisse.internal.model.SelectedItemCollection; -import com.zhihu.matisse.internal.ui.adapter.AlbumMediaAdapter; -import com.zhihu.matisse.internal.ui.widget.MediaGridInset; -import com.zhihu.matisse.internal.utils.UIUtils; - -public class MediaSelectionFragment extends Fragment implements - AlbumMediaCollection.AlbumMediaCallbacks, AlbumMediaAdapter.CheckStateListener, - AlbumMediaAdapter.OnMediaClickListener { - - public static final String EXTRA_ALBUM = "extra_album"; - - private final AlbumMediaCollection mAlbumMediaCollection = new AlbumMediaCollection(); - private RecyclerView mRecyclerView; - private AlbumMediaAdapter mAdapter; - private SelectionProvider mSelectionProvider; - private AlbumMediaAdapter.CheckStateListener mCheckStateListener; - private AlbumMediaAdapter.OnMediaClickListener mOnMediaClickListener; - - public static MediaSelectionFragment newInstance(Album album) { - MediaSelectionFragment fragment = new MediaSelectionFragment(); - Bundle args = new Bundle(); - args.putParcelable(EXTRA_ALBUM, album); - fragment.setArguments(args); - return fragment; - } - - @Override - public void onAttach(Context context) { - super.onAttach(context); - if (context instanceof SelectionProvider) { - mSelectionProvider = (SelectionProvider) context; - } else { - throw new IllegalStateException("Context must implement SelectionProvider."); - } - if (context instanceof AlbumMediaAdapter.CheckStateListener) { - mCheckStateListener = (AlbumMediaAdapter.CheckStateListener) context; - } - if (context instanceof AlbumMediaAdapter.OnMediaClickListener) { - mOnMediaClickListener = (AlbumMediaAdapter.OnMediaClickListener) context; - } - } - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - return inflater.inflate(R.layout.fragment_media_selection, container, false); - } - - @Override - public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerview); - } - - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - Album album = getArguments().getParcelable(EXTRA_ALBUM); - - mAdapter = new AlbumMediaAdapter(getContext(), - mSelectionProvider.provideSelectedItemCollection(), mRecyclerView); - mAdapter.registerCheckStateListener(this); - mAdapter.registerOnMediaClickListener(this); - mRecyclerView.setHasFixedSize(true); - - int spanCount; - SelectionSpec selectionSpec = SelectionSpec.getInstance(); - if (selectionSpec.gridExpectedSize > 0) { - spanCount = UIUtils.spanCount(getContext(), selectionSpec.gridExpectedSize); - } else { - spanCount = selectionSpec.spanCount; - } - mRecyclerView.setLayoutManager(new GridLayoutManager(getContext(), spanCount)); - - int spacing = getResources().getDimensionPixelSize(R.dimen.media_grid_spacing); - mRecyclerView.addItemDecoration(new MediaGridInset(spanCount, spacing, false)); - mRecyclerView.setAdapter(mAdapter); - mAlbumMediaCollection.onCreate(getActivity(), this); - mAlbumMediaCollection.load(album, selectionSpec.capture); - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - mAlbumMediaCollection.onDestroy(); - } - - public void refreshMediaGrid() { - mAdapter.notifyDataSetChanged(); - } - - public void refreshSelection() { - mAdapter.refreshSelection(); - } - - @Override - public void onAlbumMediaLoad(Cursor cursor) { - mAdapter.swapCursor(cursor); - } - - @Override - public void onAlbumMediaReset() { - mAdapter.swapCursor(null); - } - - @Override - public void onUpdate() { - // notify outer Activity that check state changed - if (mCheckStateListener != null) { - mCheckStateListener.onUpdate(); - } - } - - @Override - public void onMediaClick(Album album, Item item, int adapterPosition) { - if (mOnMediaClickListener != null) { - mOnMediaClickListener.onMediaClick((Album) getArguments().getParcelable(EXTRA_ALBUM), - item, adapterPosition); - } - } - - public interface SelectionProvider { - SelectedItemCollection provideSelectedItemCollection(); - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/PreviewItemFragment.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/PreviewItemFragment.java deleted file mode 100644 index ef7fb12..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/PreviewItemFragment.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui; - -import android.content.ActivityNotFoundException; -import android.content.Context; -import android.content.Intent; -import android.graphics.Point; -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Toast; - -import com.zhihu.matisse.R; -import com.zhihu.matisse.internal.entity.Item; -import com.zhihu.matisse.internal.entity.SelectionSpec; -import com.zhihu.matisse.internal.utils.PhotoMetadataUtils; -import com.zhihu.matisse.listener.OnFragmentInteractionListener; - -import it.sephiroth.android.library.imagezoom.ImageViewTouch; -import it.sephiroth.android.library.imagezoom.ImageViewTouchBase; - -public class PreviewItemFragment extends Fragment { - - private static final String ARGS_ITEM = "args_item"; - private OnFragmentInteractionListener mListener; - - public static PreviewItemFragment newInstance(Item item) { - PreviewItemFragment fragment = new PreviewItemFragment(); - Bundle bundle = new Bundle(); - bundle.putParcelable(ARGS_ITEM, item); - fragment.setArguments(bundle); - return fragment; - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - return inflater.inflate(R.layout.fragment_preview_item, container, false); - } - - @Override - public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - final Item item = getArguments().getParcelable(ARGS_ITEM); - if (item == null) { - return; - } - - View videoPlayButton = view.findViewById(R.id.video_play_button); - if (item.isVideo()) { - videoPlayButton.setVisibility(View.VISIBLE); - videoPlayButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setDataAndType(item.uri, "video/*"); - try { - startActivity(intent); - } catch (ActivityNotFoundException e) { - Toast.makeText(getContext(), R.string.error_no_video_activity, Toast.LENGTH_SHORT).show(); - } - } - }); - } else { - videoPlayButton.setVisibility(View.GONE); - } - - ImageViewTouch image = (ImageViewTouch) view.findViewById(R.id.image_view); - image.setDisplayType(ImageViewTouchBase.DisplayType.FIT_TO_SCREEN); - - image.setSingleTapListener(new ImageViewTouch.OnImageViewTouchSingleTapListener() { - @Override - public void onSingleTapConfirmed() { - if (mListener != null) { - mListener.onClick(); - } - } - }); - - Point size = PhotoMetadataUtils.getBitmapSize(item.getContentUri(), getActivity()); - if (item.isGif()) { - SelectionSpec.getInstance().imageEngine.loadGifImage(getContext(), size.x, size.y, image, - item.getContentUri()); - } else { - SelectionSpec.getInstance().imageEngine.loadImage(getContext(), size.x, size.y, image, - item.getContentUri()); - } - } - - public void resetView() { - if (getView() != null) { - ((ImageViewTouch) getView().findViewById(R.id.image_view)).resetMatrix(); - } - } - - - @Override - public void onAttach(Context context) { - super.onAttach(context); - if (context instanceof OnFragmentInteractionListener) { - mListener = (OnFragmentInteractionListener) context; - } else { - throw new RuntimeException(context.toString() - + " must implement OnFragmentInteractionListener"); - } - } - - @Override - public void onDetach() { - super.onDetach(); - mListener = null; - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/SelectedPreviewActivity.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/SelectedPreviewActivity.java deleted file mode 100644 index 4bd6e25..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/SelectedPreviewActivity.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui; - -import android.os.Bundle; -import android.support.annotation.Nullable; - -import com.zhihu.matisse.internal.entity.Item; -import com.zhihu.matisse.internal.entity.SelectionSpec; -import com.zhihu.matisse.internal.model.SelectedItemCollection; - -import java.util.List; - -public class SelectedPreviewActivity extends BasePreviewActivity { - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (!SelectionSpec.getInstance().hasInited) { - setResult(RESULT_CANCELED); - finish(); - return; - } - - Bundle bundle = getIntent().getBundleExtra(EXTRA_DEFAULT_BUNDLE); - List selected = bundle.getParcelableArrayList(SelectedItemCollection.STATE_SELECTION); - mAdapter.addAll(selected); - mAdapter.notifyDataSetChanged(); - if (mSpec.countable) { - mCheckView.setCheckedNum(1); - } else { - mCheckView.setChecked(true); - } - mPreviousPos = 0; - updateSize(selected.get(0)); - } - -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/AlbumMediaAdapter.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/AlbumMediaAdapter.java deleted file mode 100644 index 769ba1b..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/AlbumMediaAdapter.java +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui.adapter; - -import android.content.Context; -import android.content.res.TypedArray; -import android.database.Cursor; -import android.graphics.PorterDuff; -import android.graphics.drawable.Drawable; -import android.support.v7.widget.GridLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; - -import com.zhihu.matisse.R; -import com.zhihu.matisse.internal.entity.Album; -import com.zhihu.matisse.internal.entity.Item; -import com.zhihu.matisse.internal.entity.SelectionSpec; -import com.zhihu.matisse.internal.entity.IncapableCause; -import com.zhihu.matisse.internal.model.SelectedItemCollection; -import com.zhihu.matisse.internal.ui.widget.CheckView; -import com.zhihu.matisse.internal.ui.widget.MediaGrid; - -public class AlbumMediaAdapter extends - RecyclerViewCursorAdapter implements - MediaGrid.OnMediaGridClickListener { - - private static final int VIEW_TYPE_CAPTURE = 0x01; - private static final int VIEW_TYPE_MEDIA = 0x02; - private final SelectedItemCollection mSelectedCollection; - private final Drawable mPlaceholder; - private SelectionSpec mSelectionSpec; - private CheckStateListener mCheckStateListener; - private OnMediaClickListener mOnMediaClickListener; - private RecyclerView mRecyclerView; - private int mImageResize; - - public AlbumMediaAdapter(Context context, SelectedItemCollection selectedCollection, RecyclerView recyclerView) { - super(null); - mSelectionSpec = SelectionSpec.getInstance(); - mSelectedCollection = selectedCollection; - - TypedArray ta = context.getTheme().obtainStyledAttributes(new int[]{R.attr.item_placeholder}); - mPlaceholder = ta.getDrawable(0); - ta.recycle(); - - mRecyclerView = recyclerView; - } - - @Override - public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - if (viewType == VIEW_TYPE_CAPTURE) { - View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.photo_capture_item, parent, false); - CaptureViewHolder holder = new CaptureViewHolder(v); - holder.itemView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (v.getContext() instanceof OnPhotoCapture) { - ((OnPhotoCapture) v.getContext()).capture(); - } - } - }); - return holder; - } else if (viewType == VIEW_TYPE_MEDIA) { - View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.media_grid_item, parent, false); - return new MediaViewHolder(v); - } - return null; - } - - @Override - protected void onBindViewHolder(final RecyclerView.ViewHolder holder, Cursor cursor) { - if (holder instanceof CaptureViewHolder) { - CaptureViewHolder captureViewHolder = (CaptureViewHolder) holder; - Drawable[] drawables = captureViewHolder.mHint.getCompoundDrawables(); - TypedArray ta = holder.itemView.getContext().getTheme().obtainStyledAttributes( - new int[]{R.attr.capture_textColor}); - int color = ta.getColor(0, 0); - ta.recycle(); - - for (int i = 0; i < drawables.length; i++) { - Drawable drawable = drawables[i]; - if (drawable != null) { - final Drawable.ConstantState state = drawable.getConstantState(); - if (state == null) { - continue; - } - - Drawable newDrawable = state.newDrawable().mutate(); - newDrawable.setColorFilter(color, PorterDuff.Mode.SRC_IN); - newDrawable.setBounds(drawable.getBounds()); - drawables[i] = newDrawable; - } - } - captureViewHolder.mHint.setCompoundDrawables(drawables[0], drawables[1], drawables[2], drawables[3]); - } else if (holder instanceof MediaViewHolder) { - MediaViewHolder mediaViewHolder = (MediaViewHolder) holder; - - final Item item = Item.valueOf(cursor); - mediaViewHolder.mMediaGrid.preBindMedia(new MediaGrid.PreBindInfo( - getImageResize(mediaViewHolder.mMediaGrid.getContext()), - mPlaceholder, - mSelectionSpec.countable, - holder - )); - mediaViewHolder.mMediaGrid.bindMedia(item); - mediaViewHolder.mMediaGrid.setOnMediaGridClickListener(this); - setCheckStatus(item, mediaViewHolder.mMediaGrid); - } - } - - private void setCheckStatus(Item item, MediaGrid mediaGrid) { - if (mSelectionSpec.countable) { - int checkedNum = mSelectedCollection.checkedNumOf(item); - if (checkedNum > 0) { - mediaGrid.setCheckEnabled(true); - mediaGrid.setCheckedNum(checkedNum); - } else { - if (mSelectedCollection.maxSelectableReached()) { - mediaGrid.setCheckEnabled(false); - mediaGrid.setCheckedNum(CheckView.UNCHECKED); - } else { - mediaGrid.setCheckEnabled(true); - mediaGrid.setCheckedNum(checkedNum); - } - } - } else { - boolean selected = mSelectedCollection.isSelected(item); - if (selected) { - mediaGrid.setCheckEnabled(true); - mediaGrid.setChecked(true); - } else { - if (mSelectedCollection.maxSelectableReached()) { - mediaGrid.setCheckEnabled(false); - mediaGrid.setChecked(false); - } else { - mediaGrid.setCheckEnabled(true); - mediaGrid.setChecked(false); - } - } - } - } - - @Override - public void onThumbnailClicked(ImageView thumbnail, Item item, RecyclerView.ViewHolder holder) { - if (mOnMediaClickListener != null) { - mOnMediaClickListener.onMediaClick(null, item, holder.getAdapterPosition()); - } - } - - @Override - public void onCheckViewClicked(CheckView checkView, Item item, RecyclerView.ViewHolder holder) { - if (mSelectionSpec.countable) { - int checkedNum = mSelectedCollection.checkedNumOf(item); - if (checkedNum == CheckView.UNCHECKED) { - if (assertAddSelection(holder.itemView.getContext(), item)) { - mSelectedCollection.add(item); - notifyCheckStateChanged(); - } - } else { - mSelectedCollection.remove(item); - notifyCheckStateChanged(); - } - } else { - if (mSelectedCollection.isSelected(item)) { - mSelectedCollection.remove(item); - notifyCheckStateChanged(); - } else { - if (assertAddSelection(holder.itemView.getContext(), item)) { - mSelectedCollection.add(item); - notifyCheckStateChanged(); - } - } - } - } - - private void notifyCheckStateChanged() { - notifyDataSetChanged(); - if (mCheckStateListener != null) { - mCheckStateListener.onUpdate(); - } - } - - @Override - public int getItemViewType(int position, Cursor cursor) { - return Item.valueOf(cursor).isCapture() ? VIEW_TYPE_CAPTURE : VIEW_TYPE_MEDIA; - } - - private boolean assertAddSelection(Context context, Item item) { - IncapableCause cause = mSelectedCollection.isAcceptable(item); - IncapableCause.handleCause(context, cause); - return cause == null; - } - - - public void registerCheckStateListener(CheckStateListener listener) { - mCheckStateListener = listener; - } - - public void unregisterCheckStateListener() { - mCheckStateListener = null; - } - - public void registerOnMediaClickListener(OnMediaClickListener listener) { - mOnMediaClickListener = listener; - } - - public void unregisterOnMediaClickListener() { - mOnMediaClickListener = null; - } - - public void refreshSelection() { - GridLayoutManager layoutManager = (GridLayoutManager) mRecyclerView.getLayoutManager(); - int first = layoutManager.findFirstVisibleItemPosition(); - int last = layoutManager.findLastVisibleItemPosition(); - if (first == -1 || last == -1) { - return; - } - Cursor cursor = getCursor(); - for (int i = first; i <= last; i++) { - RecyclerView.ViewHolder holder = mRecyclerView.findViewHolderForAdapterPosition(first); - if (holder instanceof MediaViewHolder) { - if (cursor.moveToPosition(i)) { - setCheckStatus(Item.valueOf(cursor), ((MediaViewHolder) holder).mMediaGrid); - } - } - } - } - - private int getImageResize(Context context) { - if (mImageResize == 0) { - RecyclerView.LayoutManager lm = mRecyclerView.getLayoutManager(); - int spanCount = ((GridLayoutManager) lm).getSpanCount(); - int screenWidth = context.getResources().getDisplayMetrics().widthPixels; - int availableWidth = screenWidth - context.getResources().getDimensionPixelSize( - R.dimen.media_grid_spacing) * (spanCount - 1); - mImageResize = availableWidth / spanCount; - mImageResize = (int) (mImageResize * mSelectionSpec.thumbnailScale); - } - return mImageResize; - } - - public interface CheckStateListener { - void onUpdate(); - } - - public interface OnMediaClickListener { - void onMediaClick(Album album, Item item, int adapterPosition); - } - - public interface OnPhotoCapture { - void capture(); - } - - private static class MediaViewHolder extends RecyclerView.ViewHolder { - - private MediaGrid mMediaGrid; - - MediaViewHolder(View itemView) { - super(itemView); - mMediaGrid = (MediaGrid) itemView; - } - } - - private static class CaptureViewHolder extends RecyclerView.ViewHolder { - - private TextView mHint; - - CaptureViewHolder(View itemView) { - super(itemView); - - mHint = (TextView) itemView.findViewById(R.id.hint); - } - } - -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/AlbumsAdapter.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/AlbumsAdapter.java deleted file mode 100644 index 711e512..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/AlbumsAdapter.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui.adapter; - -import android.content.Context; -import android.content.res.TypedArray; -import android.database.Cursor; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.CursorAdapter; -import android.widget.ImageView; -import android.widget.TextView; - -import com.zhihu.matisse.R; -import com.zhihu.matisse.internal.entity.Album; -import com.zhihu.matisse.internal.entity.SelectionSpec; - -import java.io.File; - -public class AlbumsAdapter extends CursorAdapter { - - private final Drawable mPlaceholder; - - public AlbumsAdapter(Context context, Cursor c, boolean autoRequery) { - super(context, c, autoRequery); - - TypedArray ta = context.getTheme().obtainStyledAttributes( - new int[]{R.attr.album_thumbnail_placeholder}); - mPlaceholder = ta.getDrawable(0); - ta.recycle(); - } - - public AlbumsAdapter(Context context, Cursor c, int flags) { - super(context, c, flags); - - TypedArray ta = context.getTheme().obtainStyledAttributes( - new int[]{R.attr.album_thumbnail_placeholder}); - mPlaceholder = ta.getDrawable(0); - ta.recycle(); - } - - @Override - public View newView(Context context, Cursor cursor, ViewGroup parent) { - return LayoutInflater.from(context).inflate(R.layout.album_list_item, parent, false); - } - - @Override - public void bindView(View view, Context context, Cursor cursor) { - Album album = Album.valueOf(cursor); - ((TextView) view.findViewById(R.id.album_name)).setText(album.getDisplayName(context)); - ((TextView) view.findViewById(R.id.album_media_count)).setText(String.valueOf(album.getCount())); - - // do not need to load animated Gif - SelectionSpec.getInstance().imageEngine.loadThumbnail(context, context.getResources().getDimensionPixelSize(R - .dimen.media_grid_size), mPlaceholder, - (ImageView) view.findViewById(R.id.album_cover), Uri.fromFile(new File(album.getCoverPath()))); - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/PreviewPagerAdapter.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/PreviewPagerAdapter.java deleted file mode 100644 index eef46f0..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/PreviewPagerAdapter.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui.adapter; - -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentPagerAdapter; -import android.view.ViewGroup; - -import com.zhihu.matisse.internal.entity.Item; -import com.zhihu.matisse.internal.ui.PreviewItemFragment; - -import java.util.ArrayList; -import java.util.List; - -public class PreviewPagerAdapter extends FragmentPagerAdapter { - - private ArrayList mItems = new ArrayList<>(); - private OnPrimaryItemSetListener mListener; - - public PreviewPagerAdapter(FragmentManager manager, OnPrimaryItemSetListener listener) { - super(manager); - mListener = listener; - } - - @Override - public Fragment getItem(int position) { - return PreviewItemFragment.newInstance(mItems.get(position)); - } - - @Override - public int getCount() { - return mItems.size(); - } - - @Override - public void setPrimaryItem(ViewGroup container, int position, Object object) { - super.setPrimaryItem(container, position, object); - if (mListener != null) { - mListener.onPrimaryItemSet(position); - } - } - - public Item getMediaItem(int position) { - return mItems.get(position); - } - - public void addAll(List items) { - mItems.addAll(items); - } - - interface OnPrimaryItemSetListener { - - void onPrimaryItemSet(int position); - } - -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/RecyclerViewCursorAdapter.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/RecyclerViewCursorAdapter.java deleted file mode 100644 index 6557dde..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/RecyclerViewCursorAdapter.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui.adapter; - -import android.database.Cursor; -import android.provider.MediaStore; -import android.support.v7.widget.RecyclerView; - -public abstract class RecyclerViewCursorAdapter extends - RecyclerView.Adapter { - - private Cursor mCursor; - private int mRowIDColumn; - - RecyclerViewCursorAdapter(Cursor c) { - setHasStableIds(true); - swapCursor(c); - } - - protected abstract void onBindViewHolder(VH holder, Cursor cursor); - - @Override - public void onBindViewHolder(VH holder, int position) { - if (!isDataValid(mCursor)) { - throw new IllegalStateException("Cannot bind view holder when cursor is in invalid state."); - } - if (!mCursor.moveToPosition(position)) { - throw new IllegalStateException("Could not move cursor to position " + position - + " when trying to bind view holder"); - } - - onBindViewHolder(holder, mCursor); - } - - @Override - public int getItemViewType(int position) { - if (!mCursor.moveToPosition(position)) { - throw new IllegalStateException("Could not move cursor to position " + position - + " when trying to get item view type."); - } - return getItemViewType(position, mCursor); - } - - protected abstract int getItemViewType(int position, Cursor cursor); - - @Override - public int getItemCount() { - if (isDataValid(mCursor)) { - return mCursor.getCount(); - } else { - return 0; - } - } - - @Override - public long getItemId(int position) { - if (!isDataValid(mCursor)) { - throw new IllegalStateException("Cannot lookup item id when cursor is in invalid state."); - } - if (!mCursor.moveToPosition(position)) { - throw new IllegalStateException("Could not move cursor to position " + position - + " when trying to get an item id"); - } - - return mCursor.getLong(mRowIDColumn); - } - - public void swapCursor(Cursor newCursor) { - if (newCursor == mCursor) { - return; - } - - if (newCursor != null) { - mCursor = newCursor; - mRowIDColumn = mCursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns._ID); - // notify the observers about the new cursor - notifyDataSetChanged(); - } else { - notifyItemRangeRemoved(0, getItemCount()); - mCursor = null; - mRowIDColumn = -1; - } - } - - public Cursor getCursor() { - return mCursor; - } - - private boolean isDataValid(Cursor cursor) { - return cursor != null && !cursor.isClosed(); - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/AlbumsSpinner.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/AlbumsSpinner.java deleted file mode 100644 index b3c9534..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/AlbumsSpinner.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui.widget; - -import android.content.Context; -import android.content.res.TypedArray; -import android.database.Cursor; -import android.graphics.PorterDuff; -import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; -import android.support.v7.widget.ListPopupWindow; -import android.view.View; -import android.widget.AdapterView; -import android.widget.CursorAdapter; -import android.widget.TextView; - -import com.zhihu.matisse.R; -import com.zhihu.matisse.internal.entity.Album; -import com.zhihu.matisse.internal.utils.Platform; - -public class AlbumsSpinner { - - private static final int MAX_SHOWN_COUNT = 6; - private CursorAdapter mAdapter; - private TextView mSelected; - private ListPopupWindow mListPopupWindow; - private AdapterView.OnItemSelectedListener mOnItemSelectedListener; - - public AlbumsSpinner(@NonNull Context context) { - mListPopupWindow = new ListPopupWindow(context, null, R.attr.listPopupWindowStyle); - mListPopupWindow.setModal(true); - float density = context.getResources().getDisplayMetrics().density; - mListPopupWindow.setContentWidth((int) (216 * density)); - mListPopupWindow.setHorizontalOffset((int) (16 * density)); - mListPopupWindow.setVerticalOffset((int) (-48 * density)); - - mListPopupWindow.setOnItemClickListener(new AdapterView.OnItemClickListener() { - - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - AlbumsSpinner.this.onItemSelected(parent.getContext(), position); - if (mOnItemSelectedListener != null) { - mOnItemSelectedListener.onItemSelected(parent, view, position, id); - } - } - }); - } - - public void setOnItemSelectedListener(AdapterView.OnItemSelectedListener listener) { - mOnItemSelectedListener = listener; - } - - public void setSelection(Context context, int position) { - mListPopupWindow.setSelection(position); - onItemSelected(context, position); - } - - private void onItemSelected(Context context, int position) { - mListPopupWindow.dismiss(); - Cursor cursor = mAdapter.getCursor(); - cursor.moveToPosition(position); - Album album = Album.valueOf(cursor); - String displayName = album.getDisplayName(context); - if (mSelected.getVisibility() == View.VISIBLE) { - mSelected.setText(displayName); - } else { - if (Platform.hasICS()) { - mSelected.setAlpha(0.0f); - mSelected.setVisibility(View.VISIBLE); - mSelected.setText(displayName); - mSelected.animate().alpha(1.0f).setDuration(context.getResources().getInteger( - android.R.integer.config_longAnimTime)).start(); - } else { - mSelected.setVisibility(View.VISIBLE); - mSelected.setText(displayName); - } - - } - } - - public void setAdapter(CursorAdapter adapter) { - mListPopupWindow.setAdapter(adapter); - mAdapter = adapter; - } - - public void setSelectedTextView(TextView textView) { - mSelected = textView; - // tint dropdown arrow icon - Drawable[] drawables = mSelected.getCompoundDrawables(); - Drawable right = drawables[2]; - TypedArray ta = mSelected.getContext().getTheme().obtainStyledAttributes( - new int[]{R.attr.album_element_color}); - int color = ta.getColor(0, 0); - ta.recycle(); - right.setColorFilter(color, PorterDuff.Mode.SRC_IN); - - mSelected.setVisibility(View.GONE); - mSelected.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - int itemHeight = v.getResources().getDimensionPixelSize(R.dimen.album_item_height); - mListPopupWindow.setHeight( - mAdapter.getCount() > MAX_SHOWN_COUNT ? itemHeight * MAX_SHOWN_COUNT - : itemHeight * mAdapter.getCount()); - mListPopupWindow.show(); - } - }); - mSelected.setOnTouchListener(mListPopupWindow.createDragToOpenListener(mSelected)); - } - - public void setPopupAnchorView(View view) { - mListPopupWindow.setAnchorView(view); - } - -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/CheckRadioView.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/CheckRadioView.java deleted file mode 100644 index f860c58..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/CheckRadioView.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.zhihu.matisse.internal.ui.widget; - -import android.content.Context; -import android.graphics.PorterDuff; -import android.graphics.drawable.Drawable; -import android.support.v4.content.res.ResourcesCompat; -import android.support.v7.widget.AppCompatImageView; -import android.util.AttributeSet; - -import com.zhihu.matisse.R; - -public class CheckRadioView extends AppCompatImageView { - - private Drawable mDrawable; - - private int mSelectedColor; - private int mUnSelectUdColor; - - public CheckRadioView(Context context) { - super(context); - init(); - } - - - - public CheckRadioView(Context context, AttributeSet attrs) { - super(context, attrs); - init(); - } - - private void init() { - mSelectedColor = ResourcesCompat.getColor( - getResources(), R.color.zhihu_item_checkCircle_backgroundColor, - getContext().getTheme()); - mUnSelectUdColor = ResourcesCompat.getColor( - getResources(), R.color.zhihu_check_original_radio_disable, - getContext().getTheme()); - setChecked(false); - } - - public void setChecked(boolean enable) { - if (enable) { - setImageResource(R.drawable.ic_preview_radio_on); - mDrawable = getDrawable(); - mDrawable.setColorFilter(mSelectedColor, PorterDuff.Mode.SRC_IN); - } else { - setImageResource(R.drawable.ic_preview_radio_off); - mDrawable = getDrawable(); - mDrawable.setColorFilter(mUnSelectUdColor, PorterDuff.Mode.SRC_IN); - } - } - - - public void setColor(int color) { - if (mDrawable == null) { - mDrawable = getDrawable(); - } - mDrawable.setColorFilter(color, PorterDuff.Mode.SRC_IN); - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/CheckView.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/CheckView.java deleted file mode 100644 index b958113..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/CheckView.java +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui.widget; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffXfermode; -import android.graphics.RadialGradient; -import android.graphics.Rect; -import android.graphics.Shader; -import android.graphics.Typeface; -import android.graphics.drawable.Drawable; -import android.support.v4.content.res.ResourcesCompat; -import android.text.TextPaint; -import android.util.AttributeSet; -import android.view.View; - -import com.zhihu.matisse.R; - -public class CheckView extends View { - - public static final int UNCHECKED = Integer.MIN_VALUE; - private static final float STROKE_WIDTH = 3.0f; // dp - private static final float SHADOW_WIDTH = 6.0f; // dp - private static final int SIZE = 48; // dp - private static final float STROKE_RADIUS = 11.5f; // dp - private static final float BG_RADIUS = 11.0f; // dp - private static final int CONTENT_SIZE = 16; // dp - private boolean mCountable; - private boolean mChecked; - private int mCheckedNum; - private Paint mStrokePaint; - private Paint mBackgroundPaint; - private TextPaint mTextPaint; - private Paint mShadowPaint; - private Drawable mCheckDrawable; - private float mDensity; - private Rect mCheckRect; - private boolean mEnabled = true; - - public CheckView(Context context) { - super(context); - init(context); - } - - public CheckView(Context context, AttributeSet attrs) { - super(context, attrs); - init(context); - } - - public CheckView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - init(context); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - // fixed size 48dp x 48dp - int sizeSpec = MeasureSpec.makeMeasureSpec((int) (SIZE * mDensity), MeasureSpec.EXACTLY); - super.onMeasure(sizeSpec, sizeSpec); - } - - private void init(Context context) { - mDensity = context.getResources().getDisplayMetrics().density; - - mStrokePaint = new Paint(); - mStrokePaint.setAntiAlias(true); - mStrokePaint.setStyle(Paint.Style.STROKE); - mStrokePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER)); - mStrokePaint.setStrokeWidth(STROKE_WIDTH * mDensity); - TypedArray ta = getContext().getTheme().obtainStyledAttributes(new int[]{R.attr.item_checkCircle_borderColor}); - int defaultColor = ResourcesCompat.getColor( - getResources(), R.color.zhihu_item_checkCircle_borderColor, - getContext().getTheme()); - int color = ta.getColor(0, defaultColor); - ta.recycle(); - mStrokePaint.setColor(color); - - mCheckDrawable = ResourcesCompat.getDrawable(context.getResources(), - R.drawable.ic_check_white_18dp, context.getTheme()); - } - - public void setChecked(boolean checked) { - if (mCountable) { - throw new IllegalStateException("CheckView is countable, call setCheckedNum() instead."); - } - mChecked = checked; - invalidate(); - } - - public void setCountable(boolean countable) { - mCountable = countable; - } - - public void setCheckedNum(int checkedNum) { - if (!mCountable) { - throw new IllegalStateException("CheckView is not countable, call setChecked() instead."); - } - if (checkedNum != UNCHECKED && checkedNum <= 0) { - throw new IllegalArgumentException("checked num can't be negative."); - } - mCheckedNum = checkedNum; - invalidate(); - } - - public void setEnabled(boolean enabled) { - if (mEnabled != enabled) { - mEnabled = enabled; - invalidate(); - } - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - - // draw outer and inner shadow - initShadowPaint(); - canvas.drawCircle((float) SIZE * mDensity / 2, (float) SIZE * mDensity / 2, - (STROKE_RADIUS + STROKE_WIDTH / 2 + SHADOW_WIDTH) * mDensity, mShadowPaint); - - // draw white stroke - canvas.drawCircle((float) SIZE * mDensity / 2, (float) SIZE * mDensity / 2, - STROKE_RADIUS * mDensity, mStrokePaint); - - // draw content - if (mCountable) { - if (mCheckedNum != UNCHECKED) { - initBackgroundPaint(); - canvas.drawCircle((float) SIZE * mDensity / 2, (float) SIZE * mDensity / 2, - BG_RADIUS * mDensity, mBackgroundPaint); - initTextPaint(); - String text = String.valueOf(mCheckedNum); - int baseX = (int) (canvas.getWidth() - mTextPaint.measureText(text)) / 2; - int baseY = (int) (canvas.getHeight() - mTextPaint.descent() - mTextPaint.ascent()) / 2; - canvas.drawText(text, baseX, baseY, mTextPaint); - } - } else { - if (mChecked) { - initBackgroundPaint(); - canvas.drawCircle((float) SIZE * mDensity / 2, (float) SIZE * mDensity / 2, - BG_RADIUS * mDensity, mBackgroundPaint); - - mCheckDrawable.setBounds(getCheckRect()); - mCheckDrawable.draw(canvas); - } - } - - // enable hint - setAlpha(mEnabled ? 1.0f : 0.5f); - } - - private void initShadowPaint() { - if (mShadowPaint == null) { - mShadowPaint = new Paint(); - mShadowPaint.setAntiAlias(true); - // all in dp - float outerRadius = STROKE_RADIUS + STROKE_WIDTH / 2; - float innerRadius = outerRadius - STROKE_WIDTH; - float gradientRadius = outerRadius + SHADOW_WIDTH; - float stop0 = (innerRadius - SHADOW_WIDTH) / gradientRadius; - float stop1 = innerRadius / gradientRadius; - float stop2 = outerRadius / gradientRadius; - float stop3 = 1.0f; - mShadowPaint.setShader( - new RadialGradient((float) SIZE * mDensity / 2, - (float) SIZE * mDensity / 2, - gradientRadius * mDensity, - new int[]{Color.parseColor("#00000000"), Color.parseColor("#0D000000"), - Color.parseColor("#0D000000"), Color.parseColor("#00000000")}, - new float[]{stop0, stop1, stop2, stop3}, - Shader.TileMode.CLAMP)); - } - } - - private void initBackgroundPaint() { - if (mBackgroundPaint == null) { - mBackgroundPaint = new Paint(); - mBackgroundPaint.setAntiAlias(true); - mBackgroundPaint.setStyle(Paint.Style.FILL); - TypedArray ta = getContext().getTheme() - .obtainStyledAttributes(new int[]{R.attr.item_checkCircle_backgroundColor}); - int defaultColor = ResourcesCompat.getColor( - getResources(), R.color.zhihu_item_checkCircle_backgroundColor, - getContext().getTheme()); - int color = ta.getColor(0, defaultColor); - ta.recycle(); - mBackgroundPaint.setColor(color); - } - } - - private void initTextPaint() { - if (mTextPaint == null) { - mTextPaint = new TextPaint(); - mTextPaint.setAntiAlias(true); - mTextPaint.setColor(Color.WHITE); - mTextPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD)); - mTextPaint.setTextSize(12.0f * mDensity); - } - } - - // rect for drawing checked number or mark - private Rect getCheckRect() { - if (mCheckRect == null) { - int rectPadding = (int) (SIZE * mDensity / 2 - CONTENT_SIZE * mDensity / 2); - mCheckRect = new Rect(rectPadding, rectPadding, - (int) (SIZE * mDensity - rectPadding), (int) (SIZE * mDensity - rectPadding)); - } - - return mCheckRect; - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/IncapableDialog.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/IncapableDialog.java deleted file mode 100644 index 1599fce..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/IncapableDialog.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui.widget; - -import android.app.Dialog; -import android.content.DialogInterface; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.DialogFragment; -import android.support.v7.app.AlertDialog; -import android.text.TextUtils; - -import com.zhihu.matisse.R; - -public class IncapableDialog extends DialogFragment { - - public static final String EXTRA_TITLE = "extra_title"; - public static final String EXTRA_MESSAGE = "extra_message"; - - public static IncapableDialog newInstance(String title, String message) { - IncapableDialog dialog = new IncapableDialog(); - Bundle args = new Bundle(); - args.putString(EXTRA_TITLE, title); - args.putString(EXTRA_MESSAGE, message); - dialog.setArguments(args); - return dialog; - } - - @NonNull - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - String title = getArguments().getString(EXTRA_TITLE); - String message = getArguments().getString(EXTRA_MESSAGE); - - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - if (!TextUtils.isEmpty(title)) { - builder.setTitle(title); - } - if (!TextUtils.isEmpty(message)) { - builder.setMessage(message); - } - builder.setPositiveButton(R.string.button_ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - } - }); - - return builder.create(); - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/MediaGrid.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/MediaGrid.java deleted file mode 100644 index a7c2662..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/MediaGrid.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui.widget; - -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.support.v7.widget.RecyclerView; -import android.text.format.DateUtils; -import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.ImageView; -import android.widget.TextView; - -import com.zhihu.matisse.R; -import com.zhihu.matisse.internal.entity.Item; -import com.zhihu.matisse.internal.entity.SelectionSpec; - -public class MediaGrid extends SquareFrameLayout implements View.OnClickListener { - - private ImageView mThumbnail; - private CheckView mCheckView; - private ImageView mGifTag; - private TextView mVideoDuration; - - private Item mMedia; - private PreBindInfo mPreBindInfo; - private OnMediaGridClickListener mListener; - - public MediaGrid(Context context) { - super(context); - init(context); - } - - public MediaGrid(Context context, AttributeSet attrs) { - super(context, attrs); - init(context); - } - - private void init(Context context) { - LayoutInflater.from(context).inflate(R.layout.media_grid_content, this, true); - - mThumbnail = (ImageView) findViewById(R.id.media_thumbnail); - mCheckView = (CheckView) findViewById(R.id.check_view); - mGifTag = (ImageView) findViewById(R.id.gif); - mVideoDuration = (TextView) findViewById(R.id.video_duration); - - mThumbnail.setOnClickListener(this); - mCheckView.setOnClickListener(this); - } - - @Override - public void onClick(View v) { - if (mListener != null) { - if (v == mThumbnail) { - mListener.onThumbnailClicked(mThumbnail, mMedia, mPreBindInfo.mViewHolder); - } else if (v == mCheckView) { - mListener.onCheckViewClicked(mCheckView, mMedia, mPreBindInfo.mViewHolder); - } - } - } - - public void preBindMedia(PreBindInfo info) { - mPreBindInfo = info; - } - - public void bindMedia(Item item) { - mMedia = item; - setGifTag(); - initCheckView(); - setImage(); - setVideoDuration(); - } - - public Item getMedia() { - return mMedia; - } - - private void setGifTag() { - mGifTag.setVisibility(mMedia.isGif() ? View.VISIBLE : View.GONE); - } - - private void initCheckView() { - mCheckView.setCountable(mPreBindInfo.mCheckViewCountable); - } - - public void setCheckEnabled(boolean enabled) { - mCheckView.setEnabled(enabled); - } - - public void setCheckedNum(int checkedNum) { - mCheckView.setCheckedNum(checkedNum); - } - - public void setChecked(boolean checked) { - mCheckView.setChecked(checked); - } - - private void setImage() { - if (mMedia.isGif()) { - SelectionSpec.getInstance().imageEngine.loadGifThumbnail(getContext(), mPreBindInfo.mResize, - mPreBindInfo.mPlaceholder, mThumbnail, mMedia.getContentUri()); - } else { - SelectionSpec.getInstance().imageEngine.loadThumbnail(getContext(), mPreBindInfo.mResize, - mPreBindInfo.mPlaceholder, mThumbnail, mMedia.getContentUri()); - } - } - - private void setVideoDuration() { - if (mMedia.isVideo()) { - mVideoDuration.setVisibility(VISIBLE); - mVideoDuration.setText(DateUtils.formatElapsedTime(mMedia.duration / 1000)); - } else { - mVideoDuration.setVisibility(GONE); - } - } - - public void setOnMediaGridClickListener(OnMediaGridClickListener listener) { - mListener = listener; - } - - public void removeOnMediaGridClickListener() { - mListener = null; - } - - public interface OnMediaGridClickListener { - - void onThumbnailClicked(ImageView thumbnail, Item item, RecyclerView.ViewHolder holder); - - void onCheckViewClicked(CheckView checkView, Item item, RecyclerView.ViewHolder holder); - } - - public static class PreBindInfo { - int mResize; - Drawable mPlaceholder; - boolean mCheckViewCountable; - RecyclerView.ViewHolder mViewHolder; - - public PreBindInfo(int resize, Drawable placeholder, boolean checkViewCountable, - RecyclerView.ViewHolder viewHolder) { - mResize = resize; - mPlaceholder = placeholder; - mCheckViewCountable = checkViewCountable; - mViewHolder = viewHolder; - } - } - -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/MediaGridInset.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/MediaGridInset.java deleted file mode 100644 index eebcd42..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/MediaGridInset.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui.widget; - -import android.graphics.Rect; -import android.support.v7.widget.RecyclerView; -import android.view.View; - -public class MediaGridInset extends RecyclerView.ItemDecoration { - - private int mSpanCount; - private int mSpacing; - private boolean mIncludeEdge; - - public MediaGridInset(int spanCount, int spacing, boolean includeEdge) { - this.mSpanCount = spanCount; - this.mSpacing = spacing; - this.mIncludeEdge = includeEdge; - } - - @Override - public void getItemOffsets(Rect outRect, View view, RecyclerView parent, - RecyclerView.State state) { - int position = parent.getChildAdapterPosition(view); // item position - int column = position % mSpanCount; // item column - - if (mIncludeEdge) { - // spacing - column * ((1f / spanCount) * spacing) - outRect.left = mSpacing - column * mSpacing / mSpanCount; - // (column + 1) * ((1f / spanCount) * spacing) - outRect.right = (column + 1) * mSpacing / mSpanCount; - - if (position < mSpanCount) { // top edge - outRect.top = mSpacing; - } - outRect.bottom = mSpacing; // item bottom - } else { - // column * ((1f / spanCount) * spacing) - outRect.left = column * mSpacing / mSpanCount; - // spacing - (column + 1) * ((1f / spanCount) * spacing) - outRect.right = mSpacing - (column + 1) * mSpacing / mSpanCount; - if (position >= mSpanCount) { - outRect.top = mSpacing; // item top - } - } - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/PreviewViewPager.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/PreviewViewPager.java deleted file mode 100644 index 56fd370..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/PreviewViewPager.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui.widget; - -import android.content.Context; -import android.support.v4.view.ViewPager; -import android.util.AttributeSet; -import android.view.View; - -import it.sephiroth.android.library.imagezoom.ImageViewTouch; - -public class PreviewViewPager extends ViewPager { - - public PreviewViewPager(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) { - if (v instanceof ImageViewTouch) { - return ((ImageViewTouch) v).canScroll(dx) || super.canScroll(v, checkV, dx, x, y); - } - return super.canScroll(v, checkV, dx, x, y); - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/RoundedRectangleImageView.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/RoundedRectangleImageView.java deleted file mode 100644 index 2855157..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/RoundedRectangleImageView.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui.widget; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Path; -import android.graphics.RectF; -import android.support.v7.widget.AppCompatImageView; -import android.util.AttributeSet; - -public class RoundedRectangleImageView extends AppCompatImageView { - - private float mRadius; // dp - private Path mRoundedRectPath; - private RectF mRectF; - - public RoundedRectangleImageView(Context context) { - super(context); - init(context); - } - - public RoundedRectangleImageView(Context context, AttributeSet attrs) { - super(context, attrs); - init(context); - } - - public RoundedRectangleImageView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - init(context); - } - - private void init(Context context) { - float density = context.getResources().getDisplayMetrics().density; - mRadius = 2.0f * density; - mRoundedRectPath = new Path(); - mRectF = new RectF(); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - mRectF.set(0.0f, 0.0f, getMeasuredWidth(), getMeasuredHeight()); - mRoundedRectPath.addRoundRect(mRectF, mRadius, mRadius, Path.Direction.CW); - } - - @Override - protected void onDraw(Canvas canvas) { - canvas.clipPath(mRoundedRectPath); - super.onDraw(canvas); - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/SquareFrameLayout.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/SquareFrameLayout.java deleted file mode 100644 index 1f95518..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/SquareFrameLayout.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui.widget; - -import android.content.Context; -import android.util.AttributeSet; -import android.widget.FrameLayout; - -public class SquareFrameLayout extends FrameLayout { - - public SquareFrameLayout(Context context) { - super(context); - } - - public SquareFrameLayout(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, widthMeasureSpec); - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/utils/ExifInterfaceCompat.java b/matisse/src/main/java/com/zhihu/matisse/internal/utils/ExifInterfaceCompat.java deleted file mode 100644 index b2be0e4..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/utils/ExifInterfaceCompat.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.utils; - -import android.media.ExifInterface; -import android.text.TextUtils; -import android.util.Log; - -import java.io.IOException; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.TimeZone; - -/** - * Bug fixture for ExifInterface constructor. - */ -final class ExifInterfaceCompat { - private static final String TAG = ExifInterfaceCompat.class.getSimpleName(); - private static final int EXIF_DEGREE_FALLBACK_VALUE = -1; - - /** - * Do not instantiate this class. - */ - private ExifInterfaceCompat() { - } - - /** - * Creates new instance of {@link ExifInterface}. - * Original constructor won't check filename value, so if null value has been passed, - * the process will be killed because of SIGSEGV. - * Google Play crash report system cannot perceive this crash, so this method will throw - * {@link NullPointerException} when the filename is null. - * - * @param filename a JPEG filename. - * @return {@link ExifInterface} instance. - * @throws IOException something wrong with I/O. - */ - public static ExifInterface newInstance(String filename) throws IOException { - if (filename == null) throw new NullPointerException("filename should not be null"); - return new ExifInterface(filename); - } - - private static Date getExifDateTime(String filepath) { - ExifInterface exif; - try { - // ExifInterface does not check whether file path is null or not, - // so passing null file path argument to its constructor causing SIGSEGV. - // We should avoid such a situation by checking file path string. - exif = newInstance(filepath); - } catch (IOException ex) { - Log.e(TAG, "cannot read exif", ex); - return null; - } - - String date = exif.getAttribute(ExifInterface.TAG_DATETIME); - if (TextUtils.isEmpty(date)) { - return null; - } - try { - SimpleDateFormat formatter = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss"); - formatter.setTimeZone(TimeZone.getTimeZone("UTC")); - return formatter.parse(date); - } catch (ParseException e) { - Log.d(TAG, "failed to parse date taken", e); - } - return null; - } - - /** - * Read exif info and get datetime value of the photo. - * - * @param filepath to get datetime - * @return when a photo taken. - */ - public static long getExifDateTimeInMillis(String filepath) { - Date datetime = getExifDateTime(filepath); - if (datetime == null) { - return -1; - } - return datetime.getTime(); - } - - /** - * Read exif info and get orientation value of the photo. - * - * @param filepath to get exif. - * @return exif orientation value - */ - public static int getExifOrientation(String filepath) { - ExifInterface exif; - try { - // ExifInterface does not check whether file path is null or not, - // so passing null file path argument to its constructor causing SIGSEGV. - // We should avoid such a situation by checking file path string. - exif = newInstance(filepath); - } catch (IOException ex) { - Log.e(TAG, "cannot read exif", ex); - return EXIF_DEGREE_FALLBACK_VALUE; - } - - int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, EXIF_DEGREE_FALLBACK_VALUE); - if (orientation == EXIF_DEGREE_FALLBACK_VALUE) { - return 0; - } - // We only recognize a subset of orientation tag values. - switch (orientation) { - case ExifInterface.ORIENTATION_ROTATE_90: - return 90; - case ExifInterface.ORIENTATION_ROTATE_180: - return 180; - case ExifInterface.ORIENTATION_ROTATE_270: - return 270; - default: - return 0; - } - } -} \ No newline at end of file diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/utils/MediaStoreCompat.java b/matisse/src/main/java/com/zhihu/matisse/internal/utils/MediaStoreCompat.java deleted file mode 100644 index 54a10c9..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/utils/MediaStoreCompat.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.utils; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.net.Uri; -import android.os.Build; -import android.os.Environment; -import android.provider.MediaStore; -import android.support.v4.app.Fragment; -import android.support.v4.content.FileProvider; -import android.support.v4.os.EnvironmentCompat; - -import com.zhihu.matisse.internal.entity.CaptureStrategy; - -import java.io.File; -import java.io.IOException; -import java.lang.ref.WeakReference; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.List; -import java.util.Locale; - -public class MediaStoreCompat { - - private final WeakReference mContext; - private final WeakReference mFragment; - private CaptureStrategy mCaptureStrategy; - private Uri mCurrentPhotoUri; - private String mCurrentPhotoPath; - - public MediaStoreCompat(Activity activity) { - mContext = new WeakReference<>(activity); - mFragment = null; - } - - public MediaStoreCompat(Activity activity, Fragment fragment) { - mContext = new WeakReference<>(activity); - mFragment = new WeakReference<>(fragment); - } - - /** - * Checks whether the device has a camera feature or not. - * - * @param context a context to check for camera feature. - * @return true if the device has a camera feature. false otherwise. - */ - public static boolean hasCameraFeature(Context context) { - PackageManager pm = context.getApplicationContext().getPackageManager(); - return pm.hasSystemFeature(PackageManager.FEATURE_CAMERA); - } - - public void setCaptureStrategy(CaptureStrategy strategy) { - mCaptureStrategy = strategy; - } - - public void dispatchCaptureIntent(Context context, int requestCode) { - Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); - if (captureIntent.resolveActivity(context.getPackageManager()) != null) { - File photoFile = null; - try { - photoFile = createImageFile(); - } catch (IOException e) { - e.printStackTrace(); - } - - if (photoFile != null) { - mCurrentPhotoPath = photoFile.getAbsolutePath(); - mCurrentPhotoUri = FileProvider.getUriForFile(mContext.get(), - mCaptureStrategy.authority, photoFile); - captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, mCurrentPhotoUri); - captureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - List resInfoList = context.getPackageManager() - .queryIntentActivities(captureIntent, PackageManager.MATCH_DEFAULT_ONLY); - for (ResolveInfo resolveInfo : resInfoList) { - String packageName = resolveInfo.activityInfo.packageName; - context.grantUriPermission(packageName, mCurrentPhotoUri, - Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION); - } - } - if (mFragment != null) { - mFragment.get().startActivityForResult(captureIntent, requestCode); - } else { - mContext.get().startActivityForResult(captureIntent, requestCode); - } - } - } - } - - @SuppressWarnings("ResultOfMethodCallIgnored") - private File createImageFile() throws IOException { - // Create an image file name - String timeStamp = - new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date()); - String imageFileName = String.format("JPEG_%s.jpg", timeStamp); - File storageDir; - if (mCaptureStrategy.isPublic) { - storageDir = Environment.getExternalStoragePublicDirectory( - Environment.DIRECTORY_PICTURES); - if (!storageDir.exists()) storageDir.mkdirs(); - } else { - storageDir = mContext.get().getExternalFilesDir(Environment.DIRECTORY_PICTURES); - } - if (mCaptureStrategy.directory != null) { - storageDir = new File(storageDir, mCaptureStrategy.directory); - if (!storageDir.exists()) storageDir.mkdirs(); - } - - // Avoid joining path components manually - File tempFile = new File(storageDir, imageFileName); - - // Handle the situation that user's external storage is not ready - if (!Environment.MEDIA_MOUNTED.equals(EnvironmentCompat.getStorageState(tempFile))) { - return null; - } - - return tempFile; - } - - public Uri getCurrentPhotoUri() { - return mCurrentPhotoUri; - } - - public String getCurrentPhotoPath() { - return mCurrentPhotoPath; - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/utils/PathUtils.java b/matisse/src/main/java/com/zhihu/matisse/internal/utils/PathUtils.java deleted file mode 100644 index de64322..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/utils/PathUtils.java +++ /dev/null @@ -1,135 +0,0 @@ -package com.zhihu.matisse.internal.utils; - -import android.annotation.TargetApi; -import android.content.ContentUris; -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; -import android.os.Build; -import android.os.Environment; -import android.provider.DocumentsContract; -import android.provider.MediaStore; - -/** - * http://stackoverflow.com/a/27271131/4739220 - */ - -public class PathUtils { - /** - * Get a file path from a Uri. This will get the the path for Storage Access - * Framework Documents, as well as the _data field for the MediaStore and - * other file-based ContentProviders. - * - * @param context The context. - * @param uri The Uri to query. - * @author paulburke - */ - @TargetApi(Build.VERSION_CODES.KITKAT) - public static String getPath(final Context context, final Uri uri) { - // DocumentProvider - if (Platform.hasKitKat() && DocumentsContract.isDocumentUri(context, uri)) { - // ExternalStorageProvider - if (isExternalStorageDocument(uri)) { - final String docId = DocumentsContract.getDocumentId(uri); - final String[] split = docId.split(":"); - final String type = split[0]; - - if ("primary".equalsIgnoreCase(type)) { - return Environment.getExternalStorageDirectory() + "/" + split[1]; - } - - // TODO handle non-primary volumes - } else if (isDownloadsDocument(uri)) { // DownloadsProvider - - final String id = DocumentsContract.getDocumentId(uri); - final Uri contentUri = ContentUris.withAppendedId( - Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); - - return getDataColumn(context, contentUri, null, null); - } else if (isMediaDocument(uri)) { // MediaProvider - final String docId = DocumentsContract.getDocumentId(uri); - final String[] split = docId.split(":"); - final String type = split[0]; - - Uri contentUri = null; - if ("image".equals(type)) { - contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; - } else if ("video".equals(type)) { - contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; - } else if ("audio".equals(type)) { - contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; - } - - final String selection = "_id=?"; - final String[] selectionArgs = new String[]{ - split[1] - }; - - return getDataColumn(context, contentUri, selection, selectionArgs); - } - } else if ("content".equalsIgnoreCase(uri.getScheme())) { // MediaStore (and general) - return getDataColumn(context, uri, null, null); - } else if ("file".equalsIgnoreCase(uri.getScheme())) { // File - return uri.getPath(); - } - - return null; - } - - /** - * Get the value of the data column for this Uri. This is useful for - * MediaStore Uris, and other file-based ContentProviders. - * - * @param context The context. - * @param uri The Uri to query. - * @param selection (Optional) Filter used in the query. - * @param selectionArgs (Optional) Selection arguments used in the query. - * @return The value of the _data column, which is typically a file path. - */ - public static String getDataColumn(Context context, Uri uri, String selection, - String[] selectionArgs) { - - Cursor cursor = null; - final String column = "_data"; - final String[] projection = { - column - }; - - try { - cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null); - if (cursor != null && cursor.moveToFirst()) { - final int columnIndex = cursor.getColumnIndexOrThrow(column); - return cursor.getString(columnIndex); - } - } finally { - if (cursor != null) - cursor.close(); - } - return null; - } - - - /** - * @param uri The Uri to check. - * @return Whether the Uri authority is ExternalStorageProvider. - */ - public static boolean isExternalStorageDocument(Uri uri) { - return "com.android.externalstorage.documents".equals(uri.getAuthority()); - } - - /** - * @param uri The Uri to check. - * @return Whether the Uri authority is DownloadsProvider. - */ - public static boolean isDownloadsDocument(Uri uri) { - return "com.android.providers.downloads.documents".equals(uri.getAuthority()); - } - - /** - * @param uri The Uri to check. - * @return Whether the Uri authority is MediaProvider. - */ - public static boolean isMediaDocument(Uri uri) { - return "com.android.providers.media.documents".equals(uri.getAuthority()); - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/utils/PhotoMetadataUtils.java b/matisse/src/main/java/com/zhihu/matisse/internal/utils/PhotoMetadataUtils.java deleted file mode 100644 index 59c1c8c..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/utils/PhotoMetadataUtils.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (C) 2014 nohana, Inc. - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.utils; - -import android.app.Activity; -import android.content.ContentResolver; -import android.content.Context; -import android.database.Cursor; -import android.graphics.BitmapFactory; -import android.graphics.Point; -import android.media.ExifInterface; -import android.net.Uri; -import android.provider.MediaStore; -import android.util.DisplayMetrics; -import android.util.Log; - -import com.zhihu.matisse.MimeType; -import com.zhihu.matisse.R; -import com.zhihu.matisse.filter.Filter; -import com.zhihu.matisse.internal.entity.Item; -import com.zhihu.matisse.internal.entity.SelectionSpec; -import com.zhihu.matisse.internal.entity.IncapableCause; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.text.DecimalFormat; -import java.text.NumberFormat; -import java.util.Locale; - -public final class PhotoMetadataUtils { - private static final String TAG = PhotoMetadataUtils.class.getSimpleName(); - private static final int MAX_WIDTH = 1600; - private static final String SCHEME_CONTENT = "content"; - - private PhotoMetadataUtils() { - throw new AssertionError("oops! the utility class is about to be instantiated..."); - } - - public static int getPixelsCount(ContentResolver resolver, Uri uri) { - Point size = getBitmapBound(resolver, uri); - return size.x * size.y; - } - - public static Point getBitmapSize(Uri uri, Activity activity) { - ContentResolver resolver = activity.getContentResolver(); - Point imageSize = getBitmapBound(resolver, uri); - int w = imageSize.x; - int h = imageSize.y; - if (PhotoMetadataUtils.shouldRotate(resolver, uri)) { - w = imageSize.y; - h = imageSize.x; - } - if (h == 0) return new Point(MAX_WIDTH, MAX_WIDTH); - DisplayMetrics metrics = new DisplayMetrics(); - activity.getWindowManager().getDefaultDisplay().getMetrics(metrics); - float screenWidth = (float) metrics.widthPixels; - float screenHeight = (float) metrics.heightPixels; - float widthScale = screenWidth / w; - float heightScale = screenHeight / h; - if (widthScale > heightScale) { - return new Point((int) (w * widthScale), (int) (h * heightScale)); - } - return new Point((int) (w * widthScale), (int) (h * heightScale)); - } - - public static Point getBitmapBound(ContentResolver resolver, Uri uri) { - InputStream is = null; - try { - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inJustDecodeBounds = true; - is = resolver.openInputStream(uri); - BitmapFactory.decodeStream(is, null, options); - int width = options.outWidth; - int height = options.outHeight; - return new Point(width, height); - } catch (FileNotFoundException e) { - return new Point(0, 0); - } finally { - if (is != null) { - try { - is.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - } - - public static String getPath(ContentResolver resolver, Uri uri) { - if (uri == null) { - return null; - } - - if (SCHEME_CONTENT.equals(uri.getScheme())) { - Cursor cursor = null; - try { - cursor = resolver.query(uri, new String[]{MediaStore.Images.ImageColumns.DATA}, - null, null, null); - if (cursor == null || !cursor.moveToFirst()) { - return null; - } - return cursor.getString(cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA)); - } finally { - if (cursor != null) { - cursor.close(); - } - } - } - return uri.getPath(); - } - - public static IncapableCause isAcceptable(Context context, Item item) { - if (!isSelectableType(context, item)) { - return new IncapableCause(context.getString(R.string.error_file_type)); - } - - if (SelectionSpec.getInstance().filters != null) { - for (Filter filter : SelectionSpec.getInstance().filters) { - IncapableCause incapableCause = filter.filter(context, item); - if (incapableCause != null) { - return incapableCause; - } - } - } - return null; - } - - private static boolean isSelectableType(Context context, Item item) { - if (context == null) { - return false; - } - - ContentResolver resolver = context.getContentResolver(); - for (MimeType type : SelectionSpec.getInstance().mimeTypeSet) { - if (type.checkType(resolver, item.getContentUri())) { - return true; - } - } - return false; - } - - private static boolean shouldRotate(ContentResolver resolver, Uri uri) { - ExifInterface exif; - try { - exif = ExifInterfaceCompat.newInstance(getPath(resolver, uri)); - } catch (IOException e) { - Log.e(TAG, "could not read exif info of the image: " + uri); - return false; - } - int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1); - return orientation == ExifInterface.ORIENTATION_ROTATE_90 - || orientation == ExifInterface.ORIENTATION_ROTATE_270; - } - - public static float getSizeInMB(long sizeInBytes) { - DecimalFormat df = (DecimalFormat) NumberFormat.getNumberInstance(Locale.US); - df.applyPattern("0.0"); - String result = df.format((float) sizeInBytes / 1024 / 1024); - Log.e(TAG, "getSizeInMB: " + result); - result = result.replaceAll(",", "."); // in some case , 0.0 will be 0,0 - return Float.valueOf(result); - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/utils/Platform.java b/matisse/src/main/java/com/zhihu/matisse/internal/utils/Platform.java deleted file mode 100644 index df41989..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/utils/Platform.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.zhihu.matisse.internal.utils; - -import android.os.Build; - -/** - * @author JoongWon Baik - */ -public class Platform { - public static boolean hasICS() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH; - } - - public static boolean hasKitKat() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/utils/UIUtils.java b/matisse/src/main/java/com/zhihu/matisse/internal/utils/UIUtils.java deleted file mode 100644 index 129b599..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/utils/UIUtils.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.utils; - -import android.content.Context; - -public class UIUtils { - - public static int spanCount(Context context, int gridExpectedSize) { - int screenWidth = context.getResources().getDisplayMetrics().widthPixels; - float expected = (float) screenWidth / (float) gridExpectedSize; - int spanCount = Math.round(expected); - if (spanCount == 0) { - spanCount = 1; - } - return spanCount; - } - -} diff --git a/matisse/src/main/java/com/zhihu/matisse/listener/OnCheckedListener.java b/matisse/src/main/java/com/zhihu/matisse/listener/OnCheckedListener.java deleted file mode 100644 index 4a0ebae..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/listener/OnCheckedListener.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.zhihu.matisse.listener; - - -/** - * when original is enabled , callback immediately when user check or uncheck original. - */ -public interface OnCheckedListener { - void onCheck(boolean isChecked); -} diff --git a/matisse/src/main/java/com/zhihu/matisse/listener/OnFragmentInteractionListener.java b/matisse/src/main/java/com/zhihu/matisse/listener/OnFragmentInteractionListener.java deleted file mode 100644 index 79f5536..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/listener/OnFragmentInteractionListener.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.zhihu.matisse.listener; - -/** - * PreViewItemFragment 和 BasePreViewActivity 通信的接口 ,为了方便拿到 ImageViewTouch 的点击事件 - */ -public interface OnFragmentInteractionListener { - /** - * ImageViewTouch 被点击了 - */ - void onClick(); -} diff --git a/matisse/src/main/java/com/zhihu/matisse/listener/OnSelectedListener.java b/matisse/src/main/java/com/zhihu/matisse/listener/OnSelectedListener.java deleted file mode 100644 index 33e374e..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/listener/OnSelectedListener.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.zhihu.matisse.listener; - -import android.net.Uri; -import android.support.annotation.NonNull; - -import java.util.List; - -public interface OnSelectedListener { - /** - * @param uriList the selected item {@link Uri} list. - * @param pathList the selected item file path list. - */ - void onSelected(@NonNull List uriList, @NonNull List pathList); -} diff --git a/matisse/src/main/java/com/zhihu/matisse/ui/MatisseActivity.java b/matisse/src/main/java/com/zhihu/matisse/ui/MatisseActivity.java deleted file mode 100644 index 0f0322c..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/ui/MatisseActivity.java +++ /dev/null @@ -1,428 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.ui; - -import android.app.Activity; -import android.content.Intent; -import android.content.res.TypedArray; -import android.database.Cursor; -import android.graphics.PorterDuff; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; -import android.view.MenuItem; -import android.view.View; -import android.widget.AdapterView; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.zhihu.matisse.R; -import com.zhihu.matisse.internal.entity.Album; -import com.zhihu.matisse.internal.entity.Item; -import com.zhihu.matisse.internal.entity.SelectionSpec; -import com.zhihu.matisse.internal.model.AlbumCollection; -import com.zhihu.matisse.internal.model.SelectedItemCollection; -import com.zhihu.matisse.internal.ui.AlbumPreviewActivity; -import com.zhihu.matisse.internal.ui.BasePreviewActivity; -import com.zhihu.matisse.internal.ui.MediaSelectionFragment; -import com.zhihu.matisse.internal.ui.SelectedPreviewActivity; -import com.zhihu.matisse.internal.ui.adapter.AlbumMediaAdapter; -import com.zhihu.matisse.internal.ui.adapter.AlbumsAdapter; -import com.zhihu.matisse.internal.ui.widget.AlbumsSpinner; -import com.zhihu.matisse.internal.ui.widget.CheckRadioView; -import com.zhihu.matisse.internal.ui.widget.IncapableDialog; -import com.zhihu.matisse.internal.utils.MediaStoreCompat; -import com.zhihu.matisse.internal.utils.PathUtils; -import com.zhihu.matisse.internal.utils.PhotoMetadataUtils; - -import java.util.ArrayList; - -/** - * Main Activity to display albums and media content (images/videos) in each album - * and also support media selecting operations. - */ -public class MatisseActivity extends AppCompatActivity implements - AlbumCollection.AlbumCallbacks, AdapterView.OnItemSelectedListener, - MediaSelectionFragment.SelectionProvider, View.OnClickListener, - AlbumMediaAdapter.CheckStateListener, AlbumMediaAdapter.OnMediaClickListener, - AlbumMediaAdapter.OnPhotoCapture { - - public static final String EXTRA_RESULT_SELECTION = "extra_result_selection"; - public static final String EXTRA_RESULT_SELECTION_PATH = "extra_result_selection_path"; - public static final String EXTRA_RESULT_ORIGINAL_ENABLE = "extra_result_original_enable"; - private static final int REQUEST_CODE_PREVIEW = 23; - private static final int REQUEST_CODE_CAPTURE = 24; - public static final String CHECK_STATE = "checkState"; - private final AlbumCollection mAlbumCollection = new AlbumCollection(); - private MediaStoreCompat mMediaStoreCompat; - private SelectedItemCollection mSelectedCollection = new SelectedItemCollection(this); - private SelectionSpec mSpec; - - private AlbumsSpinner mAlbumsSpinner; - private AlbumsAdapter mAlbumsAdapter; - private TextView mButtonPreview; - private TextView mButtonApply; - private View mContainer; - private View mEmptyView; - - private LinearLayout mOriginalLayout; - private CheckRadioView mOriginal; - private boolean mOriginalEnable; - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - // programmatically set theme before super.onCreate() - mSpec = SelectionSpec.getInstance(); - setTheme(mSpec.themeId); - super.onCreate(savedInstanceState); - if (!mSpec.hasInited) { - setResult(RESULT_CANCELED); - finish(); - return; - } - setContentView(R.layout.activity_matisse); - - if (mSpec.needOrientationRestriction()) { - setRequestedOrientation(mSpec.orientation); - } - - if (mSpec.capture) { - mMediaStoreCompat = new MediaStoreCompat(this); - if (mSpec.captureStrategy == null) - throw new RuntimeException("Don't forget to set CaptureStrategy."); - mMediaStoreCompat.setCaptureStrategy(mSpec.captureStrategy); - } - - Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - ActionBar actionBar = getSupportActionBar(); - actionBar.setDisplayShowTitleEnabled(false); - actionBar.setDisplayHomeAsUpEnabled(true); - Drawable navigationIcon = toolbar.getNavigationIcon(); - TypedArray ta = getTheme().obtainStyledAttributes(new int[]{R.attr.album_element_color}); - int color = ta.getColor(0, 0); - ta.recycle(); - navigationIcon.setColorFilter(color, PorterDuff.Mode.SRC_IN); - - mButtonPreview = (TextView) findViewById(R.id.button_preview); - mButtonApply = (TextView) findViewById(R.id.button_apply); - mButtonPreview.setOnClickListener(this); - mButtonApply.setOnClickListener(this); - mContainer = findViewById(R.id.container); - mEmptyView = findViewById(R.id.empty_view); - mOriginalLayout = findViewById(R.id.originalLayout); - mOriginal = findViewById(R.id.original); - mOriginalLayout.setOnClickListener(this); - - mSelectedCollection.onCreate(savedInstanceState); - if (savedInstanceState != null) { - mOriginalEnable = savedInstanceState.getBoolean(CHECK_STATE); - } - updateBottomToolbar(); - - mAlbumsAdapter = new AlbumsAdapter(this, null, false); - mAlbumsSpinner = new AlbumsSpinner(this); - mAlbumsSpinner.setOnItemSelectedListener(this); - mAlbumsSpinner.setSelectedTextView((TextView) findViewById(R.id.selected_album)); - mAlbumsSpinner.setPopupAnchorView(findViewById(R.id.toolbar)); - mAlbumsSpinner.setAdapter(mAlbumsAdapter); - mAlbumCollection.onCreate(this, this); - mAlbumCollection.onRestoreInstanceState(savedInstanceState); - mAlbumCollection.loadAlbums(); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - mSelectedCollection.onSaveInstanceState(outState); - mAlbumCollection.onSaveInstanceState(outState); - outState.putBoolean("checkState", mOriginalEnable); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - mAlbumCollection.onDestroy(); - mSpec.onCheckedListener = null; - mSpec.onSelectedListener = null; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == android.R.id.home) { - onBackPressed(); - return true; - } - return super.onOptionsItemSelected(item); - } - - @Override - public void onBackPressed() { - setResult(Activity.RESULT_CANCELED); - super.onBackPressed(); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (resultCode != RESULT_OK) - return; - - if (requestCode == REQUEST_CODE_PREVIEW) { - Bundle resultBundle = data.getBundleExtra(BasePreviewActivity.EXTRA_RESULT_BUNDLE); - ArrayList selected = resultBundle.getParcelableArrayList(SelectedItemCollection.STATE_SELECTION); - mOriginalEnable = data.getBooleanExtra(BasePreviewActivity.EXTRA_RESULT_ORIGINAL_ENABLE, false); - int collectionType = resultBundle.getInt(SelectedItemCollection.STATE_COLLECTION_TYPE, - SelectedItemCollection.COLLECTION_UNDEFINED); - if (data.getBooleanExtra(BasePreviewActivity.EXTRA_RESULT_APPLY, false)) { - Intent result = new Intent(); - ArrayList selectedUris = new ArrayList<>(); - ArrayList selectedPaths = new ArrayList<>(); - if (selected != null) { - for (Item item : selected) { - selectedUris.add(item.getContentUri()); - selectedPaths.add(PathUtils.getPath(this, item.getContentUri())); - } - } - result.putParcelableArrayListExtra(EXTRA_RESULT_SELECTION, selectedUris); - result.putStringArrayListExtra(EXTRA_RESULT_SELECTION_PATH, selectedPaths); - result.putExtra(EXTRA_RESULT_ORIGINAL_ENABLE, mOriginalEnable); - setResult(RESULT_OK, result); - finish(); - } else { - mSelectedCollection.overwrite(selected, collectionType); - Fragment mediaSelectionFragment = getSupportFragmentManager().findFragmentByTag( - MediaSelectionFragment.class.getSimpleName()); - if (mediaSelectionFragment instanceof MediaSelectionFragment) { - ((MediaSelectionFragment) mediaSelectionFragment).refreshMediaGrid(); - } - updateBottomToolbar(); - } - } else if (requestCode == REQUEST_CODE_CAPTURE) { - // Just pass the data back to previous calling Activity. - Uri contentUri = mMediaStoreCompat.getCurrentPhotoUri(); - String path = mMediaStoreCompat.getCurrentPhotoPath(); - ArrayList selected = new ArrayList<>(); - selected.add(contentUri); - ArrayList selectedPath = new ArrayList<>(); - selectedPath.add(path); - Intent result = new Intent(); - result.putParcelableArrayListExtra(EXTRA_RESULT_SELECTION, selected); - result.putStringArrayListExtra(EXTRA_RESULT_SELECTION_PATH, selectedPath); - setResult(RESULT_OK, result); - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) - MatisseActivity.this.revokeUriPermission(contentUri, - Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION); - finish(); - } - } - - private void updateBottomToolbar() { - - int selectedCount = mSelectedCollection.count(); - if (selectedCount == 0) { - mButtonPreview.setEnabled(false); - mButtonApply.setEnabled(false); - mButtonApply.setText(getString(R.string.button_sure_default)); - } else if (selectedCount == 1 && mSpec.singleSelectionModeEnabled()) { - mButtonPreview.setEnabled(true); - mButtonApply.setText(R.string.button_sure_default); - mButtonApply.setEnabled(true); - } else { - mButtonPreview.setEnabled(true); - mButtonApply.setEnabled(true); - mButtonApply.setText(getString(R.string.button_sure, selectedCount)); - } - - - if (mSpec.originalable) { - mOriginalLayout.setVisibility(View.VISIBLE); - updateOriginalState(); - } else { - mOriginalLayout.setVisibility(View.INVISIBLE); - } - - - } - - - private void updateOriginalState() { - mOriginal.setChecked(mOriginalEnable); - if (countOverMaxSize() > 0) { - - if (mOriginalEnable) { - IncapableDialog incapableDialog = IncapableDialog.newInstance("", - getString(R.string.error_over_original_size, mSpec.originalMaxSize)); - incapableDialog.show(getSupportFragmentManager(), - IncapableDialog.class.getName()); - - mOriginal.setChecked(false); - mOriginalEnable = false; - } - } - } - - - private int countOverMaxSize() { - int count = 0; - int selectedCount = mSelectedCollection.count(); - for (int i = 0; i < selectedCount; i++) { - Item item = mSelectedCollection.asList().get(i); - - if (item.isImage()) { - float size = PhotoMetadataUtils.getSizeInMB(item.size); - if (size > mSpec.originalMaxSize) { - count++; - } - } - } - return count; - } - - @Override - public void onClick(View v) { - if (v.getId() == R.id.button_preview) { - Intent intent = new Intent(this, SelectedPreviewActivity.class); - intent.putExtra(BasePreviewActivity.EXTRA_DEFAULT_BUNDLE, mSelectedCollection.getDataWithBundle()); - intent.putExtra(BasePreviewActivity.EXTRA_RESULT_ORIGINAL_ENABLE, mOriginalEnable); - startActivityForResult(intent, REQUEST_CODE_PREVIEW); - } else if (v.getId() == R.id.button_apply) { - Intent result = new Intent(); - ArrayList selectedUris = (ArrayList) mSelectedCollection.asListOfUri(); - result.putParcelableArrayListExtra(EXTRA_RESULT_SELECTION, selectedUris); - ArrayList selectedPaths = (ArrayList) mSelectedCollection.asListOfString(); - result.putStringArrayListExtra(EXTRA_RESULT_SELECTION_PATH, selectedPaths); - result.putExtra(EXTRA_RESULT_ORIGINAL_ENABLE, mOriginalEnable); - setResult(RESULT_OK, result); - finish(); - } else if (v.getId() == R.id.originalLayout) { - int count = countOverMaxSize(); - if (count > 0) { - IncapableDialog incapableDialog = IncapableDialog.newInstance("", - getString(R.string.error_over_original_count, count, mSpec.originalMaxSize)); - incapableDialog.show(getSupportFragmentManager(), - IncapableDialog.class.getName()); - return; - } - - mOriginalEnable = !mOriginalEnable; - mOriginal.setChecked(mOriginalEnable); - - if (mSpec.onCheckedListener != null) { - mSpec.onCheckedListener.onCheck(mOriginalEnable); - } - } - } - - @Override - public void onItemSelected(AdapterView parent, View view, int position, long id) { - mAlbumCollection.setStateCurrentSelection(position); - mAlbumsAdapter.getCursor().moveToPosition(position); - Album album = Album.valueOf(mAlbumsAdapter.getCursor()); - if (album.isAll() && SelectionSpec.getInstance().capture) { - album.addCaptureCount(); - } - onAlbumSelected(album); - } - - @Override - public void onNothingSelected(AdapterView parent) { - - } - - @Override - public void onAlbumLoad(final Cursor cursor) { - mAlbumsAdapter.swapCursor(cursor); - // select default album. - Handler handler = new Handler(Looper.getMainLooper()); - handler.post(new Runnable() { - - @Override - public void run() { - cursor.moveToPosition(mAlbumCollection.getCurrentSelection()); - mAlbumsSpinner.setSelection(MatisseActivity.this, - mAlbumCollection.getCurrentSelection()); - Album album = Album.valueOf(cursor); - if (album.isAll() && SelectionSpec.getInstance().capture) { - album.addCaptureCount(); - } - onAlbumSelected(album); - } - }); - } - - @Override - public void onAlbumReset() { - mAlbumsAdapter.swapCursor(null); - } - - private void onAlbumSelected(Album album) { - if (album.isAll() && album.isEmpty()) { - mContainer.setVisibility(View.GONE); - mEmptyView.setVisibility(View.VISIBLE); - } else { - mContainer.setVisibility(View.VISIBLE); - mEmptyView.setVisibility(View.GONE); - Fragment fragment = MediaSelectionFragment.newInstance(album); - getSupportFragmentManager() - .beginTransaction() - .replace(R.id.container, fragment, MediaSelectionFragment.class.getSimpleName()) - .commitAllowingStateLoss(); - } - } - - @Override - public void onUpdate() { - // notify bottom toolbar that check state changed. - updateBottomToolbar(); - - if (mSpec.onSelectedListener != null) { - mSpec.onSelectedListener.onSelected( - mSelectedCollection.asListOfUri(), mSelectedCollection.asListOfString()); - } - } - - @Override - public void onMediaClick(Album album, Item item, int adapterPosition) { - Intent intent = new Intent(this, AlbumPreviewActivity.class); - intent.putExtra(AlbumPreviewActivity.EXTRA_ALBUM, album); - intent.putExtra(AlbumPreviewActivity.EXTRA_ITEM, item); - intent.putExtra(BasePreviewActivity.EXTRA_DEFAULT_BUNDLE, mSelectedCollection.getDataWithBundle()); - intent.putExtra(BasePreviewActivity.EXTRA_RESULT_ORIGINAL_ENABLE, mOriginalEnable); - startActivityForResult(intent, REQUEST_CODE_PREVIEW); - } - - @Override - public SelectedItemCollection provideSelectedItemCollection() { - return mSelectedCollection; - } - - @Override - public void capture() { - if (mMediaStoreCompat != null) { - mMediaStoreCompat.dispatchCaptureIntent(this, REQUEST_CODE_CAPTURE); - } - } - -} diff --git a/matisse/src/main/res/color/dracula_bottom_toolbar_apply.xml b/matisse/src/main/res/color/dracula_bottom_toolbar_apply.xml deleted file mode 100644 index 84e13af..0000000 --- a/matisse/src/main/res/color/dracula_bottom_toolbar_apply.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/matisse/src/main/res/color/dracula_bottom_toolbar_preview.xml b/matisse/src/main/res/color/dracula_bottom_toolbar_preview.xml deleted file mode 100644 index 56e04b7..0000000 --- a/matisse/src/main/res/color/dracula_bottom_toolbar_preview.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/matisse/src/main/res/color/dracula_preview_bottom_toolbar_apply.xml b/matisse/src/main/res/color/dracula_preview_bottom_toolbar_apply.xml deleted file mode 100644 index 9920c27..0000000 --- a/matisse/src/main/res/color/dracula_preview_bottom_toolbar_apply.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/matisse/src/main/res/color/zhihu_bottom_toolbar_apply.xml b/matisse/src/main/res/color/zhihu_bottom_toolbar_apply.xml deleted file mode 100644 index d12c968..0000000 --- a/matisse/src/main/res/color/zhihu_bottom_toolbar_apply.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/matisse/src/main/res/color/zhihu_bottom_toolbar_preview.xml b/matisse/src/main/res/color/zhihu_bottom_toolbar_preview.xml deleted file mode 100644 index fef8d16..0000000 --- a/matisse/src/main/res/color/zhihu_bottom_toolbar_preview.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/matisse/src/main/res/color/zhihu_preview_bottom_toolbar_apply.xml b/matisse/src/main/res/color/zhihu_preview_bottom_toolbar_apply.xml deleted file mode 100644 index 0bec454..0000000 --- a/matisse/src/main/res/color/zhihu_preview_bottom_toolbar_apply.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - diff --git a/matisse/src/main/res/drawable-hdpi/ic_arrow_drop_down_white_24dp.png b/matisse/src/main/res/drawable-hdpi/ic_arrow_drop_down_white_24dp.png deleted file mode 100644 index 4c6076d..0000000 Binary files a/matisse/src/main/res/drawable-hdpi/ic_arrow_drop_down_white_24dp.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-hdpi/ic_check_white_18dp.png b/matisse/src/main/res/drawable-hdpi/ic_check_white_18dp.png deleted file mode 100644 index 08dbac9..0000000 Binary files a/matisse/src/main/res/drawable-hdpi/ic_check_white_18dp.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-hdpi/ic_empty_dracula.png b/matisse/src/main/res/drawable-hdpi/ic_empty_dracula.png deleted file mode 100644 index 0920df4..0000000 Binary files a/matisse/src/main/res/drawable-hdpi/ic_empty_dracula.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-hdpi/ic_empty_zhihu.png b/matisse/src/main/res/drawable-hdpi/ic_empty_zhihu.png deleted file mode 100644 index 86ffe1c..0000000 Binary files a/matisse/src/main/res/drawable-hdpi/ic_empty_zhihu.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-hdpi/ic_gif.png b/matisse/src/main/res/drawable-hdpi/ic_gif.png deleted file mode 100644 index d4085f5..0000000 Binary files a/matisse/src/main/res/drawable-hdpi/ic_gif.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-hdpi/ic_play_circle_outline_white_48dp.png b/matisse/src/main/res/drawable-hdpi/ic_play_circle_outline_white_48dp.png deleted file mode 100644 index 6e1b578..0000000 Binary files a/matisse/src/main/res/drawable-hdpi/ic_play_circle_outline_white_48dp.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-hdpi/ic_preview_radio_off.webp b/matisse/src/main/res/drawable-hdpi/ic_preview_radio_off.webp deleted file mode 100644 index 80930b9..0000000 Binary files a/matisse/src/main/res/drawable-hdpi/ic_preview_radio_off.webp and /dev/null differ diff --git a/matisse/src/main/res/drawable-hdpi/ic_preview_radio_on.webp b/matisse/src/main/res/drawable-hdpi/ic_preview_radio_on.webp deleted file mode 100644 index 89ff580..0000000 Binary files a/matisse/src/main/res/drawable-hdpi/ic_preview_radio_on.webp and /dev/null differ diff --git a/matisse/src/main/res/drawable-mdpi/ic_arrow_drop_down_white_24dp.png b/matisse/src/main/res/drawable-mdpi/ic_arrow_drop_down_white_24dp.png deleted file mode 100644 index 4046a74..0000000 Binary files a/matisse/src/main/res/drawable-mdpi/ic_arrow_drop_down_white_24dp.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-mdpi/ic_check_white_18dp.png b/matisse/src/main/res/drawable-mdpi/ic_check_white_18dp.png deleted file mode 100644 index ad14847..0000000 Binary files a/matisse/src/main/res/drawable-mdpi/ic_check_white_18dp.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-mdpi/ic_empty_dracula.png b/matisse/src/main/res/drawable-mdpi/ic_empty_dracula.png deleted file mode 100644 index 34937ef..0000000 Binary files a/matisse/src/main/res/drawable-mdpi/ic_empty_dracula.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-mdpi/ic_empty_zhihu.png b/matisse/src/main/res/drawable-mdpi/ic_empty_zhihu.png deleted file mode 100644 index f5628ee..0000000 Binary files a/matisse/src/main/res/drawable-mdpi/ic_empty_zhihu.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-mdpi/ic_gif.png b/matisse/src/main/res/drawable-mdpi/ic_gif.png deleted file mode 100644 index aeeb0d4..0000000 Binary files a/matisse/src/main/res/drawable-mdpi/ic_gif.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-mdpi/ic_play_circle_outline_white_48dp.png b/matisse/src/main/res/drawable-mdpi/ic_play_circle_outline_white_48dp.png deleted file mode 100644 index 615b80d..0000000 Binary files a/matisse/src/main/res/drawable-mdpi/ic_play_circle_outline_white_48dp.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-mdpi/ic_preview_radio_off.webp b/matisse/src/main/res/drawable-mdpi/ic_preview_radio_off.webp deleted file mode 100644 index 1a8f6c1..0000000 Binary files a/matisse/src/main/res/drawable-mdpi/ic_preview_radio_off.webp and /dev/null differ diff --git a/matisse/src/main/res/drawable-mdpi/ic_preview_radio_on.webp b/matisse/src/main/res/drawable-mdpi/ic_preview_radio_on.webp deleted file mode 100644 index b336c9c..0000000 Binary files a/matisse/src/main/res/drawable-mdpi/ic_preview_radio_on.webp and /dev/null differ diff --git a/matisse/src/main/res/drawable-xhdpi/ic_arrow_drop_down_white_24dp.png b/matisse/src/main/res/drawable-xhdpi/ic_arrow_drop_down_white_24dp.png deleted file mode 100644 index da239e4..0000000 Binary files a/matisse/src/main/res/drawable-xhdpi/ic_arrow_drop_down_white_24dp.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-xhdpi/ic_check_white_18dp.png b/matisse/src/main/res/drawable-xhdpi/ic_check_white_18dp.png deleted file mode 100644 index 729f290..0000000 Binary files a/matisse/src/main/res/drawable-xhdpi/ic_check_white_18dp.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-xhdpi/ic_empty_dracula.png b/matisse/src/main/res/drawable-xhdpi/ic_empty_dracula.png deleted file mode 100644 index 2cd36f6..0000000 Binary files a/matisse/src/main/res/drawable-xhdpi/ic_empty_dracula.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-xhdpi/ic_empty_zhihu.png b/matisse/src/main/res/drawable-xhdpi/ic_empty_zhihu.png deleted file mode 100644 index c223b56..0000000 Binary files a/matisse/src/main/res/drawable-xhdpi/ic_empty_zhihu.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-xhdpi/ic_gif.png b/matisse/src/main/res/drawable-xhdpi/ic_gif.png deleted file mode 100644 index ed2a70b..0000000 Binary files a/matisse/src/main/res/drawable-xhdpi/ic_gif.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-xhdpi/ic_play_circle_outline_white_48dp.png b/matisse/src/main/res/drawable-xhdpi/ic_play_circle_outline_white_48dp.png deleted file mode 100644 index 516f643..0000000 Binary files a/matisse/src/main/res/drawable-xhdpi/ic_play_circle_outline_white_48dp.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-xhdpi/ic_preview_radio_off.webp b/matisse/src/main/res/drawable-xhdpi/ic_preview_radio_off.webp deleted file mode 100644 index b13bb1b..0000000 Binary files a/matisse/src/main/res/drawable-xhdpi/ic_preview_radio_off.webp and /dev/null differ diff --git a/matisse/src/main/res/drawable-xhdpi/ic_preview_radio_on.webp b/matisse/src/main/res/drawable-xhdpi/ic_preview_radio_on.webp deleted file mode 100644 index 632b2a7..0000000 Binary files a/matisse/src/main/res/drawable-xhdpi/ic_preview_radio_on.webp and /dev/null differ diff --git a/matisse/src/main/res/drawable-xxhdpi/ic_arrow_drop_down_white_24dp.png b/matisse/src/main/res/drawable-xxhdpi/ic_arrow_drop_down_white_24dp.png deleted file mode 100644 index c19c19d..0000000 Binary files a/matisse/src/main/res/drawable-xxhdpi/ic_arrow_drop_down_white_24dp.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-xxhdpi/ic_check_white_18dp.png b/matisse/src/main/res/drawable-xxhdpi/ic_check_white_18dp.png deleted file mode 100644 index 9e3f948..0000000 Binary files a/matisse/src/main/res/drawable-xxhdpi/ic_check_white_18dp.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-xxhdpi/ic_empty_dracula.png b/matisse/src/main/res/drawable-xxhdpi/ic_empty_dracula.png deleted file mode 100644 index daaedc8..0000000 Binary files a/matisse/src/main/res/drawable-xxhdpi/ic_empty_dracula.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-xxhdpi/ic_empty_zhihu.png b/matisse/src/main/res/drawable-xxhdpi/ic_empty_zhihu.png deleted file mode 100644 index c7b14e4..0000000 Binary files a/matisse/src/main/res/drawable-xxhdpi/ic_empty_zhihu.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-xxhdpi/ic_gif.png b/matisse/src/main/res/drawable-xxhdpi/ic_gif.png deleted file mode 100644 index 2803825..0000000 Binary files a/matisse/src/main/res/drawable-xxhdpi/ic_gif.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-xxhdpi/ic_play_circle_outline_white_48dp.png b/matisse/src/main/res/drawable-xxhdpi/ic_play_circle_outline_white_48dp.png deleted file mode 100644 index 0311f89..0000000 Binary files a/matisse/src/main/res/drawable-xxhdpi/ic_play_circle_outline_white_48dp.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-xxxhdpi/ic_arrow_drop_down_white_24dp.png b/matisse/src/main/res/drawable-xxxhdpi/ic_arrow_drop_down_white_24dp.png deleted file mode 100644 index 452e502..0000000 Binary files a/matisse/src/main/res/drawable-xxxhdpi/ic_arrow_drop_down_white_24dp.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-xxxhdpi/ic_check_white_18dp.png b/matisse/src/main/res/drawable-xxxhdpi/ic_check_white_18dp.png deleted file mode 100644 index 2c2ad77..0000000 Binary files a/matisse/src/main/res/drawable-xxxhdpi/ic_check_white_18dp.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-xxxhdpi/ic_empty_dracula.png b/matisse/src/main/res/drawable-xxxhdpi/ic_empty_dracula.png deleted file mode 100644 index 4fc34d8..0000000 Binary files a/matisse/src/main/res/drawable-xxxhdpi/ic_empty_dracula.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-xxxhdpi/ic_empty_zhihu.png b/matisse/src/main/res/drawable-xxxhdpi/ic_empty_zhihu.png deleted file mode 100644 index 9b3c3f1..0000000 Binary files a/matisse/src/main/res/drawable-xxxhdpi/ic_empty_zhihu.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-xxxhdpi/ic_gif.png b/matisse/src/main/res/drawable-xxxhdpi/ic_gif.png deleted file mode 100644 index d9d6433..0000000 Binary files a/matisse/src/main/res/drawable-xxxhdpi/ic_gif.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-xxxhdpi/ic_photo_camera_white_24dp.png b/matisse/src/main/res/drawable-xxxhdpi/ic_photo_camera_white_24dp.png deleted file mode 100644 index 777658e..0000000 Binary files a/matisse/src/main/res/drawable-xxxhdpi/ic_photo_camera_white_24dp.png and /dev/null differ diff --git a/matisse/src/main/res/drawable-xxxhdpi/ic_play_circle_outline_white_48dp.png b/matisse/src/main/res/drawable-xxxhdpi/ic_play_circle_outline_white_48dp.png deleted file mode 100644 index 7a5a168..0000000 Binary files a/matisse/src/main/res/drawable-xxxhdpi/ic_play_circle_outline_white_48dp.png and /dev/null differ diff --git a/matisse/src/main/res/layout/activity_matisse.xml b/matisse/src/main/res/layout/activity_matisse.xml deleted file mode 100644 index 821a0b3..0000000 --- a/matisse/src/main/res/layout/activity_matisse.xml +++ /dev/null @@ -1,137 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/matisse/src/main/res/layout/activity_media_preview.xml b/matisse/src/main/res/layout/activity_media_preview.xml deleted file mode 100644 index e9fc349..0000000 --- a/matisse/src/main/res/layout/activity_media_preview.xml +++ /dev/null @@ -1,130 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/matisse/src/main/res/layout/album_list_item.xml b/matisse/src/main/res/layout/album_list_item.xml deleted file mode 100644 index 1fc8d2f..0000000 --- a/matisse/src/main/res/layout/album_list_item.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/matisse/src/main/res/layout/fragment_media_selection.xml b/matisse/src/main/res/layout/fragment_media_selection.xml deleted file mode 100644 index 5298172..0000000 --- a/matisse/src/main/res/layout/fragment_media_selection.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - diff --git a/matisse/src/main/res/layout/fragment_preview_item.xml b/matisse/src/main/res/layout/fragment_preview_item.xml deleted file mode 100644 index 2cfc58d..0000000 --- a/matisse/src/main/res/layout/fragment_preview_item.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - diff --git a/matisse/src/main/res/layout/media_grid_content.xml b/matisse/src/main/res/layout/media_grid_content.xml deleted file mode 100644 index 711557c..0000000 --- a/matisse/src/main/res/layout/media_grid_content.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/matisse/src/main/res/layout/media_grid_item.xml b/matisse/src/main/res/layout/media_grid_item.xml deleted file mode 100644 index 392e38b..0000000 --- a/matisse/src/main/res/layout/media_grid_item.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - \ No newline at end of file diff --git a/matisse/src/main/res/layout/photo_capture_item.xml b/matisse/src/main/res/layout/photo_capture_item.xml deleted file mode 100644 index 9c30942..0000000 --- a/matisse/src/main/res/layout/photo_capture_item.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/matisse/src/main/res/values-ar/strings.xml b/matisse/src/main/res/values-ar/strings.xml deleted file mode 100644 index 784cc64..0000000 --- a/matisse/src/main/res/values-ar/strings.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - جميع وسائل الإعلام - - معاينة - تطبيق - تطبيق (%1$d) - رجوع - كاميرا - لا وسائل الإعلام حتى الآن - تم - - لقد وصلت إلى الحد الأقصى للاختيار - يمكنك تحديد ما يصل إلى %1$d من ملفات الوسائط فقط - تحت الجودة - فوق الجودة - نوع ملف غير مدعوم - لا يمكن تحديد الصور ومقاطع الفيديو في نفس الوقت - لم يتم العثور على التطبيق دعم معاينة الفيديو - diff --git a/matisse/src/main/res/values-ca/strings.xml b/matisse/src/main/res/values-ca/strings.xml deleted file mode 100644 index 0611d09..0000000 --- a/matisse/src/main/res/values-ca/strings.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - Tots - - Previsualitza - Selecciona - Selecciona(%1$d) - Enrere - Càmera - Cap arxiu seleccionat - OK - - Has sobrepassat el màxim d\'arxius seleccionables - Només pots seleccionar fins a %1$d arxius multimedia - Baixa qualitat - Excés qualitat - Tipus d\'arxiu no permés - No es poden seleccionar imatges i vídeos al mateix temps - No s\'ha trobat cap app que suporti la previsualització de vídeo - diff --git a/matisse/src/main/res/values-de/strings.xml b/matisse/src/main/res/values-de/strings.xml deleted file mode 100644 index b92112b..0000000 --- a/matisse/src/main/res/values-de/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - Alle Medien - - Vorschau - Auswählen - Auswählen(%1$d) - Zurück - Kamera - Keine Medien gewählt - OK - - Sie haben die maximale Anzahl an Medien ausgewählt. - Sie können nur %1$d Medien auswählen - Unter Qualität - Über Qualität - Dateityp nicht unterstützt - Sie können Bilder und Videos nicht gleichzeitig auswählen - Keine App zur Videovorschau gefunden - diff --git a/matisse/src/main/res/values-es/strings.xml b/matisse/src/main/res/values-es/strings.xml deleted file mode 100644 index 5339a3b..0000000 --- a/matisse/src/main/res/values-es/strings.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - Todos - - Previsualizar - Seleccionar - Seleccionar(%1$d) - Atrás - Cámara - Ningún archivo seleccionado - OK - - Has alcanzado el máximo de archivos seleccionables - Sólo puede seleccionar hasta %1$d archivos multimedia - Baja calidad - Exceso calidad - Tipo de fichero no soportado - No se puede seleccionar imágenes y vídeos al mismo tiempo - No se ha encontrado ninguna app que soporte la previsualización de vídeo - diff --git a/matisse/src/main/res/values-it/strings.xml b/matisse/src/main/res/values-it/strings.xml deleted file mode 100644 index fbf5082..0000000 --- a/matisse/src/main/res/values-it/strings.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - Tutti i media - - Anteprima - Conferma - Conferma(%1$d) - Indietro - Camera - Nessun media disponibile - OK - - Hai selezionato il numero massimo di elementi - Puoi selezionare fino a %1$d elementi - Sotto qualità - Sopra qualità - Tipo di file non supportato - Non è possibile selezionare contemporaneamente immagini e video - Non è stata trovata alcuna app che supporti l\'anteprima video - diff --git a/matisse/src/main/res/values-ko/strings.xml b/matisse/src/main/res/values-ko/strings.xml deleted file mode 100644 index 7612d66..0000000 --- a/matisse/src/main/res/values-ko/strings.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - 전체보기 - 미리보기 - 카메라 - 비디오 미리보기를 지원하는 앱을 찾을 수 없습니다. - 이미지와 비디오는 동시에 선택 할 수 없습니다. - 적용 - 적용(%1$d) - 뒤로 - 미디어 파일이 없습니다. - 확인 - 더이상 선택할 수 없습니다. - 최대 %1$d까지 선택 가능합니다. - 화질이 너무 낮습니다. - 화질이 너무 높습니다. - 지원되지 않는 파일 유형입니다. - \ No newline at end of file diff --git a/matisse/src/main/res/values-pl/strings.xml b/matisse/src/main/res/values-pl/strings.xml deleted file mode 100644 index 739aead..0000000 --- a/matisse/src/main/res/values-pl/strings.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - Wszystkie Media - - Preview - Zatwierdź - Zatwierdź(%1$d) - Wstecz - Aparat - Brak mediów - OK - - Osiągnąłeś limit wybieralnych elementów - Możesz wybrać do %1$d plików - Poniżej jakości - Powyżej jakości - Niewspierany typ pliku - Nie można wybierać obrazów i filmów w tym samym czasie - Nie znaleziono aplikacji wspierającej podgląd wideo - Oryginał - Zatwierdź - Zatwierdź(%1$d) - diff --git a/matisse/src/main/res/values-pt-rBR/strings.xml b/matisse/src/main/res/values-pt-rBR/strings.xml deleted file mode 100644 index 75447a0..0000000 --- a/matisse/src/main/res/values-pt-rBR/strings.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - Todas as mídias - - Pré-visualizaçao - Aplicar - Aplicar(%1$d) - Voltar - Câmera - Nenhuma mídia disponível - OK - - Você atingiu o máximo de itens possíveis para seleção - Você só pode selecionar até %1$d arquivos de mídia - Abaixo da qualidade - Acima da qualidade - Tipo de arquivo não suportado - Não é possível selecionar arquivos de imagem e vídeo simultaneamente - Nenhum player de vídeo disponível para reprodução - diff --git a/matisse/src/main/res/values-ru/strings.xml b/matisse/src/main/res/values-ru/strings.xml deleted file mode 100644 index 2be64f2..0000000 --- a/matisse/src/main/res/values-ru/strings.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - Все - - Предпросмотр - Применить - Применить(%1$d) - Назад - Камера - Пусто - OK - - Вы выбрали максимальное количество файлов - - Можно выбрать не более %1$d файла - Можно выбрать не более %1$d файлов - Можно выбрать не более %1$d файлов - Можно выбрать не более %1$d файлов - - Слишком низкое качество - Слишком высокое качество - Неподдерживаемый тип файла - Невозможно выбрать изображения и видео одновременно - Приложение для предпросмотра видео не найдено - Оригинал - Применить(%1$d) - Применить - diff --git a/matisse/src/main/res/values-tr-rTR/strings.xml b/matisse/src/main/res/values-tr-rTR/strings.xml deleted file mode 100644 index 671e3fb..0000000 --- a/matisse/src/main/res/values-tr-rTR/strings.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - Tüm Medya - - Ön İzleme - Uygula - Uygula(%1$d) - Geri - Kamera - Henüz medya yok - TAMAM - - Maksimum seçilebilir değere ulaştınız - Sadece %1$d medya dosyasını seçebilirsiniz - Düşük kalite - Yüksek kalite - Desteklenmeyen dosya tipi - Görüntüleri ve videoları aynı anda seçemezsiniz - Video önizlemesini destekleyen hiçbir uygulama bulunamadı - \ No newline at end of file diff --git a/matisse/src/main/res/values-uk/strings.xml b/matisse/src/main/res/values-uk/strings.xml deleted file mode 100644 index 97cea27..0000000 --- a/matisse/src/main/res/values-uk/strings.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - Всі - - Перегляд - Застосувати - Застосувати(%1$d) - Назад - Камера - Пусто - OK - - Вы обрали максимальну кількість файлів - - Можливо обрати не більше %1$d файла - Можливо обрати не більше %1$d файлів - Можливо обрати не більше %1$d файлів - Можливо обрати не більше %1$d файлів - - Занадто низька якість - Занадто висока якість - Непідтримуваний тип файла - Неможливо обрати зображення і відео одночасно - Застосунок для перегляду відео не знайдений - diff --git a/matisse/src/main/res/values-zh-rTW/strings.xml b/matisse/src/main/res/values-zh-rTW/strings.xml deleted file mode 100644 index fc77408..0000000 --- a/matisse/src/main/res/values-zh-rTW/strings.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - 全部 - - 預覽 - 使用 - 使用(%1$d) - 返回 - 拍一張 - 還沒有圖片或影片 - 我知道了 - - 您已經達到最大選擇數量 - 最多只能選擇 %1$d 個文件 - 圖片質量太低 - 圖片質量太高 - 不支援的文件類型 - 不能同時選擇圖片和影片 - 沒有支持影片預覽的應用程式 - 原圖 - 确定 - 确定(%1$d) - \ No newline at end of file diff --git a/matisse/src/main/res/values-zh/strings.xml b/matisse/src/main/res/values-zh/strings.xml deleted file mode 100644 index 853ea42..0000000 --- a/matisse/src/main/res/values-zh/strings.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - 全部 - - 预览 - 使用 - 使用(%1$d) - 返回 - 拍一张 - 还没有图片或视频 - 我知道了 - - 您已经达到最大选择数量 - 最多只能选择 %1$d 个文件 - 图片质量太低 - 图片质量太高 - 不支持的文件类型 - 不能同时选择图片和视频 - 没有支持视频预览的应用 - "该照片大于 %1$d M,无法上传将取消勾选原图" - "有 %1$d 张照片大于 %2$d M\n无法上传,将取消勾选原图" - 原图 - 确定 - 确定(%1$d) - \ No newline at end of file diff --git a/matisse/src/main/res/values/attrs.xml b/matisse/src/main/res/values/attrs.xml deleted file mode 100644 index 852a3e3..0000000 --- a/matisse/src/main/res/values/attrs.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/matisse/src/main/res/values/colors.xml b/matisse/src/main/res/values/colors.xml deleted file mode 100644 index 24ec1f9..0000000 --- a/matisse/src/main/res/values/colors.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - #CC000000 - #61FFFFFF - - \ No newline at end of file diff --git a/matisse/src/main/res/values/colors_dracula.xml b/matisse/src/main/res/values/colors_dracula.xml deleted file mode 100644 index e8bb64f..0000000 --- a/matisse/src/main/res/values/colors_dracula.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - #263237 - #1D282C - - #34474E - #DEFFFFFF - #89FFFFFF - #455A64 - #4DFFFFFF - - #37474F - #263237 - #FFFFFF - #FFFFFF - - #232E32 - #34474E - - #DEFFFFFF - #4DFFFFFF - #03A9F4 - #4D03A9F4 - - #FFFFFF - #03A9F4 - #4D03A9F4 - \ No newline at end of file diff --git a/matisse/src/main/res/values/colors_zhihu.xml b/matisse/src/main/res/values/colors_zhihu.xml deleted file mode 100644 index 4cf43fa..0000000 --- a/matisse/src/main/res/values/colors_zhihu.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - #1E8AE8 - #176EB9 - - #FFFFFF - #DE000000 - #999999 - #EAEEF4 - #4D000000 - - #EAEEF4 - #1E8AE8 - #FFFFFF - #424242 - - #FFFFFF - #FFFFFF - - #DE000000 - #4D000000 - #0077D9 - #4D0077D9 - - #FFFFFF - #0077D9 - #4D0077D9 - - #808080 - \ No newline at end of file diff --git a/matisse/src/main/res/values/dimens.xml b/matisse/src/main/res/values/dimens.xml deleted file mode 100644 index f32d77a..0000000 --- a/matisse/src/main/res/values/dimens.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - 48dp - 4dp - - 72dp - \ No newline at end of file diff --git a/matisse/src/main/res/values/strings.xml b/matisse/src/main/res/values/strings.xml deleted file mode 100644 index 819a12a..0000000 --- a/matisse/src/main/res/values/strings.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - All Media - - Preview - Apply - Apply(%1$d) - Back - Camera - No media yet - OK - - You have reached max selectable - You can only select up to %1$d media files - Under quality - Over quality - Unsupported file type - Can\'t select images and videos at the same time - No App found supporting video preview - Can\'t select the images larger than %1$d MB - %1$d images over %2$d MB. Original will be unchecked - Original - Sure - Sure(%1$d) - diff --git a/matisse/src/main/res/values/styles.xml b/matisse/src/main/res/values/styles.xml deleted file mode 100644 index c1f9441..0000000 --- a/matisse/src/main/res/values/styles.xml +++ /dev/null @@ -1,86 +0,0 @@ - - - - - //====================================== Theme Zhihu =========================================== - - - - - - - - //===================================== Theme Dracula ========================================== - - - - - - - - \ No newline at end of file diff --git a/media/.gitignore b/media/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/media/.gitignore @@ -0,0 +1 @@ +/build diff --git a/media/build.gradle b/media/build.gradle new file mode 100644 index 0000000..3e2f2fb --- /dev/null +++ b/media/build.gradle @@ -0,0 +1,53 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 28 + + + + defaultConfig { + minSdkVersion 15 + targetSdkVersion 28 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + +} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + //annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0' + api files('libs/systembartint-1.0.4.jar') + implementation project(':compress') + def versions = rootProject.ext.dependencies + implementation versions.rxlifecycleComponents + implementation versions.appcompatV7 + implementation versions.supportV4 + implementation versions.constraint + implementation versions.recyclerview + implementation versions.projectview + implementation versions.glide + implementation versions.design + implementation versions.PhotoView + implementation versions.eventbus + implementation versions.ucrop + implementation 'com.android.support.constraint:constraint-layout:1.1.3' + testImplementation versions.junit + androidTestImplementation versions.runner + androidTestImplementation versions.espresso +} +allprojects { + repositories { + maven { url 'https://jitpack.io' } + } +} \ No newline at end of file diff --git a/app/libs/systembartint-1.0.4.jar b/media/libs/systembartint-1.0.4.jar similarity index 100% rename from app/libs/systembartint-1.0.4.jar rename to media/libs/systembartint-1.0.4.jar diff --git a/media/proguard-rules.pro b/media/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/media/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/media/src/main/AndroidManifest.xml b/media/src/main/AndroidManifest.xml new file mode 100644 index 0000000..75f2268 --- /dev/null +++ b/media/src/main/AndroidManifest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + diff --git a/media/src/main/java/com/example/media/MediaSelector.java b/media/src/main/java/com/example/media/MediaSelector.java new file mode 100644 index 0000000..e2b97cd --- /dev/null +++ b/media/src/main/java/com/example/media/MediaSelector.java @@ -0,0 +1,131 @@ +package com.example.media; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Color; +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.ColorRes; +import android.support.annotation.NonNull; +import android.support.v4.app.Fragment; + +import com.example.media.activity.MediaActivity; +import com.example.media.bean.MediaSelectorFile; +import com.example.media.resolver.Contast; + +import java.lang.ref.SoftReference; +import java.util.List; + +public class MediaSelector { + private MediaOptions mMediaOptions = MediaSelector.getDefaultOptions(); + private SoftReference mSoftActivity; + private SoftReference mSoftFragment; + + private MediaSelector(Activity activity) { + mSoftActivity = new SoftReference<>(activity); + } + + private MediaSelector(Fragment fragment) { + mSoftFragment = new SoftReference<>(fragment); + } + + public static MediaSelector with(Activity activity) { + return new MediaSelector(activity); + } + + public static MediaSelector with(Fragment fragment) { + return new MediaSelector(fragment); + } + + public MediaSelector setMediaOptions(@NonNull MediaOptions options) { + this.mMediaOptions = options; + return this; + } + + public void openMediaActivity() { + if (mSoftActivity != null && mSoftActivity.get() != null) { + Activity activity = mSoftActivity.get(); + Intent intent = new Intent(activity, MediaActivity.class); + intent.putExtra(Contast.KEY_OPEN_MEDIA, mMediaOptions); + activity.startActivityForResult(intent, Contast.CODE_REQUEST_MEDIA); + } else if (mSoftFragment != null && mSoftFragment.get() != null) { + Fragment fragment = mSoftFragment.get(); + Intent intent = new Intent(fragment.getContext(), MediaActivity.class); + intent.putExtra(Contast.KEY_OPEN_MEDIA, mMediaOptions); + fragment.startActivityForResult(intent, Contast.CODE_REQUEST_MEDIA); + } + } + + public static List resultMediaFile(Intent data) { + if (data == null) + return null; + return data.getParcelableArrayListExtra(Contast.KEY_REQUEST_MEDIA_DATA); + } + + + public static class MediaOptions implements Parcelable { + public MediaOptions() { + } + + public int maxChooseMedia = Contast.MAX_CHOOSE_MEDIA; + public boolean isCompress; + public boolean isShowCamera; + public boolean isShowVideo; + public @ColorRes + int themeColor = R.color.colorTheme; + public boolean isCrop; + public int scaleX = 1; + public int scaleY = 1; + public int cropWidth = 720; + public int cropHeight = 720; + + + protected MediaOptions(Parcel in) { + maxChooseMedia = in.readInt(); + isCompress = in.readByte() != 0; + isShowCamera = in.readByte() != 0; + isShowVideo = in.readByte() != 0; + themeColor = in.readInt(); + isCrop = in.readByte() != 0; + scaleX = in.readInt(); + scaleY = in.readInt(); + cropWidth = in.readInt(); + cropHeight = in.readInt(); + } + + public static final Creator CREATOR = new Creator() { + @Override + public MediaOptions createFromParcel(Parcel in) { + return new MediaOptions(in); + } + + @Override + public MediaOptions[] newArray(int size) { + return new MediaOptions[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(maxChooseMedia); + dest.writeByte((byte) (isCompress ? 1 : 0)); + dest.writeByte((byte) (isShowCamera ? 1 : 0)); + dest.writeByte((byte) (isShowVideo ? 1 : 0)); + dest.writeInt(themeColor); + dest.writeByte((byte) (isCrop ? 1 : 0)); + dest.writeInt(scaleX); + dest.writeInt(scaleY); + dest.writeInt(cropWidth); + dest.writeInt(cropHeight); + } + } + + public static MediaOptions getDefaultOptions() { + return new MediaOptions(); + } +} diff --git a/media/src/main/java/com/example/media/OnRecyclerItemClickListener.java b/media/src/main/java/com/example/media/OnRecyclerItemClickListener.java new file mode 100644 index 0000000..7644952 --- /dev/null +++ b/media/src/main/java/com/example/media/OnRecyclerItemClickListener.java @@ -0,0 +1,8 @@ +package com.example.media; + +import android.support.annotation.NonNull; +import android.view.View; + +public interface OnRecyclerItemClickListener { + void itemClick(@NonNull View view, int position); +} diff --git a/media/src/main/java/com/example/media/activity/BaseActivity.java b/media/src/main/java/com/example/media/activity/BaseActivity.java new file mode 100644 index 0000000..93616f3 --- /dev/null +++ b/media/src/main/java/com/example/media/activity/BaseActivity.java @@ -0,0 +1,95 @@ +package com.example.media.activity; + +import android.os.Build; +import android.os.Bundle; +import android.support.annotation.ColorRes; +import android.support.annotation.Nullable; +import android.support.v4.content.ContextCompat; +import android.view.WindowManager; + +import com.example.media.R; +import com.example.media.bean.MediaSelectorFile; +import com.example.media.permission.PermissionActivity; +import com.example.media.resolver.ActivityManger; +import com.readystatesoftware.systembartint.SystemBarTintManager; + +import org.greenrobot.eventbus.EventBus; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import utils.bean.ImageConfig; +import utils.task.CompressImageTask; + +public abstract class BaseActivity extends PermissionActivity { + + protected SystemBarTintManager mSystemBarTintManager; + private @ColorRes + int mThemeColor = R.color.colorTheme; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + } + setContentView(getLayoutId()); + initPermission(); + + } + + protected void initPermission() { + ActivityManger.get().addActivity(this); + initView(); + initData(); + initEvent(); + initUI(); + } + + protected int getThemeColor() { + return mThemeColor; + } + + protected void initUI() { + mSystemBarTintManager = new SystemBarTintManager(this); + mSystemBarTintManager.setStatusBarTintEnabled(true); + mSystemBarTintManager.setStatusBarTintColor(ContextCompat.getColor(this, getThemeColor())); + } + + @Override + protected void onDestroy() { + ActivityManger.get().removeActivity(getClass().getSimpleName()); + super.onDestroy(); + } + + protected abstract void initView(); + + protected abstract void initData(); + + protected abstract void initEvent(); + + protected abstract int getLayoutId(); + + + protected void registerEventBus() { + if (!EventBus.getDefault().isRegistered(this)) { + EventBus.getDefault().register(this); + } + } + + protected void unRegisterEventBus() { + if (EventBus.getDefault().isRegistered(this)) { + EventBus.getDefault().unregister(this); + } + } + + protected void compressImage(List mMediaFileData, CompressImageTask.OnImagesResult onImagesResult) { + final List configData = new ArrayList<>(); + for (int i = 0; i < mMediaFileData.size(); i++) { + configData.add(MediaSelectorFile.thisToDefaultImageConfig(mMediaFileData.get(i))); + } + + CompressImageTask.get().compressImages(this, configData, onImagesResult); + } +} diff --git a/media/src/main/java/com/example/media/activity/MediaActivity.java b/media/src/main/java/com/example/media/activity/MediaActivity.java new file mode 100644 index 0000000..c4e5cc4 --- /dev/null +++ b/media/src/main/java/com/example/media/activity/MediaActivity.java @@ -0,0 +1,462 @@ +package com.example.media.activity; + +import android.Manifest; +import android.app.Activity; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.net.Uri; +import android.os.Parcelable; +import android.provider.MediaStore; +import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; +import android.support.v7.app.AlertDialog; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.View; + +import com.bumptech.glide.Glide; +import com.example.item.weight.TitleView; +import com.example.media.MediaSelector; +import com.example.media.OnRecyclerItemClickListener; +import com.example.media.R; +import com.example.media.adapter.MediaFileAdapter; +import com.example.media.bean.MediaSelectorFile; +import com.example.media.bean.MediaSelectorFolder; +import com.example.media.permission.imp.OnPermissionsResult; +import com.example.media.resolver.Contast; +import com.example.media.resolver.ILoadMediaResult; +import com.example.media.resolver.MediaHelper; +import com.example.media.utils.FileUtils; +import com.example.media.weight.DialogHelper; +import com.example.media.weight.FolderWindow; +import com.example.media.weight.Toasts; + +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import utils.bean.ImageConfig; +import utils.task.CompressImageTask; + +public class MediaActivity extends BaseActivity { + + private TitleView mTvTop; + private TitleView mTvBottom; + private RecyclerView mRecyclerView; + private MediaFileAdapter mMediaFileAdapter; + private List mMediaFileData; + private List mMediaFolderData; + private FolderWindow mFolderWindow; + private List mCheckMediaFileData; + private MediaSelector.MediaOptions mOptions; + private File mCameraFile; + private AlertDialog mCameraPermissionDialog; + + + @Override + protected int getLayoutId() { + return R.layout.activity_media; + } + + @Override + protected void initPermission() { + + requestExternalStoragePermission(); + + + } + + @Override + protected int getThemeColor() { + return mOptions.themeColor; + } + + private void requestExternalStoragePermission() { + requestPermission(new OnPermissionsResult() { + @Override + public void onAllow(List list) { + MediaActivity.super.initPermission(); + } + + @Override + public void onNoAllow(List list) { + AlertDialog dialog = DialogHelper.with().createDialog(MediaActivity.this, getString(R.string.hint), getString(R.string.what_permission_is_must, getString(R.string.memory_card)), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + requestExternalStoragePermission(); + } + }); + dialog.show(); + } + + @Override + public void onForbid(List list) { + showForbidPermissionDialog(); + } + }, Manifest.permission.WRITE_EXTERNAL_STORAGE); + } + + private void showNoCameraAllowDialog(Context context, String title, String message) { + if (mCameraPermissionDialog == null) { + mCameraPermissionDialog = DialogHelper.with().createDialog(context, title, message, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + mCameraPermissionDialog.dismiss(); + } + }, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + openCamera(); + } + }); + } + if (!mCameraPermissionDialog.isShowing()) { + mCameraPermissionDialog.show(); + } + } + + @Override + protected void onStart() { + super.onStart(); + Glide.with(this).onStart(); + } + + @Override + protected void onStop() { + + super.onStop(); + + Glide.with(this).onStop(); + } + + @Override + protected void onDestroy() { + unRegisterEventBus(); + super.onDestroy(); + } + + @Override + protected void initView() { + registerEventBus(); + mTvTop = findViewById(R.id.ctv_top); + mTvBottom = findViewById(R.id.ctv_bottom); + mRecyclerView = findViewById(R.id.ry_data); + mRecyclerView.setLayoutManager(new GridLayoutManager(this, 4)); + } + + @Override + protected void initData() { + initIntent(); + MediaHelper mediaHelper = new MediaHelper(this); + mCheckMediaFileData = new ArrayList<>(); + + if (mMediaFileAdapter == null) { + + mMediaFileAdapter = new MediaFileAdapter(this, mMediaFileData,mOptions); + mRecyclerView.setAdapter(mMediaFileAdapter); + } + mediaHelper.loadMedia(mOptions.isShowCamera, mOptions.isShowVideo, new ILoadMediaResult() { + @Override + public void mediaResult(List data) { + if (data != null && data.size() > 0) { + mMediaFileData.addAll(data.get(0).fileData); + if (mMediaFolderData == null) { + mMediaFolderData = data; + } else { + mMediaFolderData.addAll(data); + } + mMediaFileAdapter.notifyDataSetChanged(); + } + + } + }); + } + + private void initIntent() { + mMediaFileData = new ArrayList<>(); + Intent intent = getIntent(); + mOptions = intent.getParcelableExtra(Contast.KEY_OPEN_MEDIA); + if (mOptions == null) { + mOptions = MediaSelector.getDefaultOptions(); + } else { + if (mOptions.maxChooseMedia <= 0) { + mOptions.maxChooseMedia = 1; + } + mTvTop.mViewRoot.setBackgroundColor(ContextCompat.getColor(this,mOptions.themeColor)); + mTvBottom.mViewRoot.setBackgroundColor(ContextCompat.getColor(this,mOptions.themeColor)); + } + + } + + private void resultMediaData() { + if (mCheckMediaFileData.size() > 0) { + if (mOptions.isCompress && !mOptions.isShowVideo) { + compressImage(mCheckMediaFileData, new CompressImageTask.OnImagesResult() { + @Override + public void startCompress() { + + } + + @Override + public void resultFilesSucceed(List list) { + mCheckMediaFileData.clear(); + for (File file : list) { + mCheckMediaFileData.add(MediaSelectorFile.checkFileToThis(file)); + } + resultMediaIntent(); + } + + @Override + public void resultFilesError() { + + } + }); + + } else { + resultMediaIntent(); + } + + } + } + + private void resultMediaIntent() { + Intent intent = new Intent(); + intent.putParcelableArrayListExtra(Contast.KEY_REQUEST_MEDIA_DATA, (ArrayList) mCheckMediaFileData); + setResult(Contast.CODE_RESULT_MEDIA, intent); + finish(); + } + + @Override + protected void initEvent() { + mTvTop.setOnSureViewClickListener(new TitleView.OnSureViewClickListener() { + @Override + public void onSureClick(@NonNull View view) { + resultMediaData(); + } + }); + mTvBottom.setOnTitleViewClickListener(new TitleView.OnTitleViewClickListener() { + @Override + public void onBackClick(@NonNull View view) { + showMediaFolderWindows(view); + } + + @Override + public void onSureClick(@NonNull View view) { + if (mCheckMediaFileData.size() > 0) { + toPreviewActivity(0, mCheckMediaFileData, mCheckMediaFileData); + } + + } + }); + mMediaFileAdapter.setOnRecyclerItemClickListener(new OnRecyclerItemClickListener() { + @Override + public void itemClick(@NonNull View view, int position) { + if (mMediaFileData.get(position).isShowCamera) { + openCamera(); + } else { + toPreviewActivity(position, mMediaFileData, mCheckMediaFileData); + } + } + }); + + + mMediaFileAdapter.setOnCheckMediaListener(new MediaFileAdapter.OnCheckMediaListener() { + @Override + public void onChecked(boolean isCheck, int position) { + if (isCheck) { + mMediaFileData.get(position).isCheck = false; + mCheckMediaFileData.remove(mMediaFileData.get(position)); + } else { + if (mCheckMediaFileData.size() < mOptions.maxChooseMedia) { + mMediaFileData.get(position).isCheck = true; + mCheckMediaFileData.add(mMediaFileData.get(position)); + } else { + Toasts.with().showToast(MediaActivity.this, getString(R.string.max_choose_media, String.valueOf(mOptions.maxChooseMedia))); + } + } + setSureStatus(); + mMediaFileAdapter.notifyItemChanged(position); + } + }); + mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { + super.onScrollStateChanged(recyclerView, newState); + if (newState == 0) { + Glide.with(MediaActivity.this).resumeRequests(); + } else { + Glide.with(MediaActivity.this).pauseRequests(); + } + } + + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + super.onScrolled(recyclerView, dx, dy); + } + }); + } + + /** + * 打开相机 + */ + private void openCamera() { + requestPermission(new OnPermissionsResult() { + @Override + public void onAllow(List list) { + Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + cameraIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + if (cameraIntent.resolveActivity(getPackageManager()) != null) { + mCameraFile = FileUtils.resultImageFile(MediaActivity.this); + Uri cameraUri = FileUtils.fileToUri(MediaActivity.this, mCameraFile, cameraIntent); + cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, cameraUri); + startActivityForResult(cameraIntent, Contast.REQUEST_CAMERA_CODE); + } + } + + @Override + public void onNoAllow(List list) { + showNoCameraAllowDialog(MediaActivity.this, getString(R.string.hint), getString(R.string.what_permission_is_must, getString(R.string.camera))); + } + + @Override + public void onForbid(List list) { + + showForbidPermissionDialog(); + + } + }, Manifest.permission.CAMERA); + } + + private void toPreviewActivity(int position, @NonNull List data, @NonNull List checkData) { + Intent intent = new Intent(MediaActivity.this, PreviewActivity.class); + intent.putParcelableArrayListExtra(Contast.KEY_PREVIEW_DATA_MEDIA, (ArrayList) data); + intent.putParcelableArrayListExtra(Contast.KEY_PREVIEW_CHECK_MEDIA, (ArrayList) checkData); + intent.putExtra(Contast.KEY_OPEN_MEDIA, mOptions); + intent.putExtra(Contast.KEY_PREVIEW_POSITION, position); + startActivity(intent); + } + + + private void showMediaFolderWindows(View view) { + + if (mFolderWindow == null) { + mFolderWindow = new FolderWindow(this, mMediaFolderData); + mFolderWindow.setOnPopupItemClickListener(new FolderWindow.OnPopupItemClickListener() { + @Override + public void onItemClick(@NonNull View view, int position) { + clickCheckFolder(position); + } + }); + mFolderWindow.showWindows(view); + } else if (mFolderWindow.getFolderWindow().isShowing()) { + mFolderWindow.dismissWindows(); + } else { + mFolderWindow.showWindows(view); + } + + + } + + private void setSureStatus() { + if (mCheckMediaFileData.size() > 0) { + mTvTop.mTvSure.setClickable(true); + mTvTop.mTvSure.setTextColor(ContextCompat.getColor(MediaActivity.this, R.color.colorTextSelector)); + mTvTop.mTvSure.setText(getString(R.string.complete_count, String.valueOf(mCheckMediaFileData.size()), String.valueOf(mOptions.maxChooseMedia))); + } else { + mTvTop.mTvSure.setClickable(false); + mTvTop.mTvSure.setTextColor(ContextCompat.getColor(MediaActivity.this, R.color.colorTextUnSelector)); + mTvTop.mTvSure.setText(R.string.sure); + + } + } + + private void clickCheckFolder(int position) { + mTvBottom.mTvBack.setText(mMediaFolderData.get(position).folderName); + mMediaFileData.clear(); + mMediaFileData.addAll(mMediaFolderData.get(position).fileData); + mMediaFileAdapter.notifyDataSetChanged(); + } + + @Override + public void onBackPressed() { + if (mFolderWindow != null && mFolderWindow.getFolderWindow().isShowing()) { + mFolderWindow.getFolderWindow().dismiss(); + } else { + super.onBackPressed(); + } + } + + /** + * 预览图片选择发送事件 + * + * @param mediaSelectorFile + */ + @Subscribe(threadMode = ThreadMode.MAIN, sticky = true) + public void previewMediaResult(@NonNull MediaSelectorFile mediaSelectorFile) { + if (mediaSelectorFile.isCheck) { + //首先先判断选择的媒体库 + if (!mCheckMediaFileData.contains(mediaSelectorFile)) { + mCheckMediaFileData.add(mediaSelectorFile); + } + + } else { + if (mCheckMediaFileData.contains(mediaSelectorFile)) { + mCheckMediaFileData.remove(mediaSelectorFile); + } + } + for (int i = 0; i < mMediaFolderData.size(); i++) { + if (mMediaFolderData.get(i).fileData.contains(mediaSelectorFile)) { + mMediaFolderData.get(i).fileData.get(mMediaFolderData.get(i).fileData.indexOf(mediaSelectorFile)).isCheck = mediaSelectorFile.isCheck; + } + } + setSureStatus(); + mMediaFileAdapter.notifyDataSetChanged(); + } + + /** + * 预览图片返回 + * + * @param checkMediaData + */ + @Subscribe(threadMode = ThreadMode.MAIN, sticky = true) + public void resultCheckMediaData(@NonNull List checkMediaData) { + if (checkMediaData.size() > 0) { + mCheckMediaFileData.clear(); + mCheckMediaFileData.addAll(checkMediaData); + resultMediaIntent(); + } + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + switch (resultCode) { + case Activity.RESULT_OK: + if (requestCode == Contast.REQUEST_CAMERA_CODE) { + if (FileUtils.existsFile(mCameraFile.getAbsolutePath())) { + FileUtils.scanImage(this, mCameraFile); + MediaSelectorFile mediaSelectorFile = MediaSelectorFile.checkFileToThis(mCameraFile); + if (mediaSelectorFile.hasData()) { + mCheckMediaFileData.add(mediaSelectorFile); + } + resultMediaData(); + } + + } + break; + + } + } +} diff --git a/media/src/main/java/com/example/media/activity/PreviewActivity.java b/media/src/main/java/com/example/media/activity/PreviewActivity.java new file mode 100644 index 0000000..6d2cfcb --- /dev/null +++ b/media/src/main/java/com/example/media/activity/PreviewActivity.java @@ -0,0 +1,345 @@ +package com.example.media.activity; + +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.content.Intent; +import android.graphics.Color; +import android.net.Uri; +import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; +import android.support.v4.view.ViewPager; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.view.animation.LinearInterpolator; +import android.widget.LinearLayout; +import android.widget.Toast; + +import com.example.item.weight.TitleView; +import com.example.media.MediaSelector; +import com.example.media.OnRecyclerItemClickListener; +import com.example.media.R; +import com.example.media.adapter.MediaCheckAdapter; +import com.example.media.adapter.PreviewAdapter; +import com.example.media.bean.MediaSelectorFile; +import com.example.media.resolver.ActivityManger; +import com.example.media.resolver.Contast; +import com.example.media.utils.FileUtils; +import com.example.media.utils.ScreenUtils; +import com.example.media.weight.PreviewViewPager; +import com.example.media.weight.Toasts; +import com.yalantis.ucrop.UCrop; + +import org.greenrobot.eventbus.EventBus; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import utils.bean.ImageConfig; +import utils.task.CompressImageTask; + +public class PreviewActivity extends BaseActivity { + + private PreviewViewPager mVpPreview; + private TitleView mTvTop; + private TitleView mTvBottom; + private List mMediaFileData; + private PreviewAdapter mPreviewAdapter; + private boolean isShowTitleView = true; + private int mPreviewPosition; + private RecyclerView mRvCheckMedia; + private View mLlBottom; + private List mCheckMediaData; + private MediaCheckAdapter mCheckAdapter; + private AnimatorSet mAnimatorSet; + private MediaSelector.MediaOptions mOptions; + + + @Override + protected int getThemeColor() { + return mOptions.themeColor; + } + + @Override + protected void initView() { + mVpPreview = findViewById(R.id.vp_preview); + ViewGroup.LayoutParams layoutParams = mVpPreview.getLayoutParams(); + layoutParams.width = ScreenUtils.screenWidth(this); + layoutParams.height = ScreenUtils.screenHeight(this); + mVpPreview.setLayoutParams(layoutParams); + mTvTop = findViewById(R.id.ctv_top); + mRvCheckMedia = findViewById(R.id.rv_check_media); + mRvCheckMedia.setLayoutManager(new LinearLayoutManager(this, LinearLayout.HORIZONTAL, false)); + mTvBottom = findViewById(R.id.ctv_bottom); + mLlBottom = findViewById(R.id.ll_bottom); + } + + @Override + protected void initData() { + Intent intent = getIntent(); + mCheckMediaData = intent.getParcelableArrayListExtra(Contast.KEY_PREVIEW_CHECK_MEDIA); + if (mCheckMediaData == null) { + mCheckMediaData = new ArrayList<>(); + } + mMediaFileData = intent.getParcelableArrayListExtra(Contast.KEY_PREVIEW_DATA_MEDIA); + mPreviewPosition = intent.getIntExtra(Contast.KEY_PREVIEW_POSITION, 0); + mOptions = intent.getParcelableExtra(Contast.KEY_OPEN_MEDIA); + mTvTop.mViewRoot.setBackgroundColor(ContextCompat.getColor(this, mOptions.themeColor)); + if (mMediaFileData == null || mMediaFileData.size() == 0) { + Toasts.with().showToast(this, "没有预览媒体库文件"); + finish(); + return; + } + if (mMediaFileData.get(0).isShowCamera && mMediaFileData.get(0).filePath == null) { + mMediaFileData.remove(0); + mPreviewPosition--; + } + + if (mCheckMediaData != null && mCheckMediaData.size() > 0) { + for (int i = 0; i < mCheckMediaData.size(); i++) { + if (!mMediaFileData.contains(mCheckMediaData.get(i))) { + mMediaFileData.add(mCheckMediaData.get(i)); + } + } + } + mTvTop.mTvBack.setText(getString(R.string.count_sum_count, String.valueOf(mPreviewPosition + 1), String.valueOf(mMediaFileData.size()))); + setTitleViewSureText(); + mTvBottom.mTvSure.setCompoundDrawablesWithIntrinsicBounds(mMediaFileData.get(mPreviewPosition).isCheck ? R.mipmap.icon_preview_check : R.mipmap.icon_preview_uncheck, 0, 0, 0); + mPreviewAdapter = new PreviewAdapter(mMediaFileData); + mVpPreview.setAdapter(mPreviewAdapter); + mVpPreview.setCurrentItem(mPreviewPosition, true); + mVpPreview.setPageTransformer(true, new PreviewAdapter.PreviewPageTransformer()); + + mCheckAdapter = new MediaCheckAdapter(this, mCheckMediaData); + mRvCheckMedia.setAdapter(mCheckAdapter); + mCheckAdapter.notifyCheckData(mMediaFileData.get(mPreviewPosition)); + initAdapterEvent(); + } + + private void setTitleViewSureText() { + if (mCheckMediaData.size() > 0) { + mTvTop.mTvSure.setText(getString(R.string.complete_count, String.valueOf(mCheckMediaData.size()), String.valueOf(mOptions.maxChooseMedia))); + } else { + mTvTop.mTvSure.setText(R.string.sure); + } + } + + private void initAdapterEvent() { + mVpPreview.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { + @Override + public void onPageScrolled(int i, float v, int i1) { + + } + + @Override + public void onPageSelected(int i) { + mPreviewPosition = i; + mTvTop.mTvBack.setText(getString(R.string.count_sum_count, String.valueOf(i + 1), String.valueOf(mMediaFileData.size()))); + mTvBottom.mTvSure.setCompoundDrawablesWithIntrinsicBounds(mMediaFileData.get(i).isCheck ? R.mipmap.icon_preview_check : R.mipmap.icon_preview_uncheck, 0, 0, 0); + mCheckAdapter.notifyCheckData(mMediaFileData.get(mPreviewPosition)); + if (mCheckMediaData.contains(mMediaFileData.get(mPreviewPosition))) { + mRvCheckMedia.scrollToPosition(mCheckMediaData.indexOf(mMediaFileData.get(mPreviewPosition))); + } + } + + @Override + public void onPageScrollStateChanged(int i) { + + } + }); + mPreviewAdapter.setOnPreviewViewClickListener(new PreviewAdapter.OnPreviewViewClickListener() { + @Override + public void onPreviewView(View view) { + if (mAnimatorSet != null && mAnimatorSet.isRunning()) { + mAnimatorSet.end(); + } + titleViewAnimation(); + isShowTitleView = !isShowTitleView; + } + }); + mPreviewAdapter.setOnPreviewVideoClickListener(new PreviewAdapter.OnPreviewVideoClickListener() { + @Override + public void onClickVideo(View view, int position) { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setDataAndType(Uri.parse(mMediaFileData.get(position).filePath), "video/*"); + startActivityForResult(intent, Contast.CODE_REQUEST_PRIVIEW_VIDEO); + } + }); + mCheckAdapter.setOnRecyclerItemClickListener(new OnRecyclerItemClickListener() { + @Override + public void itemClick(@NonNull View view, int position) { + if (mMediaFileData.contains(mCheckMediaData.get(position))) { + mVpPreview.setCurrentItem(mMediaFileData.indexOf(mCheckMediaData.get(position)), true); + mCheckAdapter.notifyDataSetChanged(); + } + + } + }); + } + + @Override + protected void initEvent() { + + mTvBottom.setOnSureViewClickListener(new TitleView.OnSureViewClickListener() { + @Override + public void onSureClick(@NonNull View view) { + if (mCheckMediaData.size() < mOptions.maxChooseMedia || (mCheckMediaData.size() == mOptions.maxChooseMedia && mMediaFileData.get(mPreviewPosition).isCheck)) { + mMediaFileData.get(mPreviewPosition).isCheck = !mMediaFileData.get(mPreviewPosition).isCheck; + mTvBottom.mTvSure.setCompoundDrawablesWithIntrinsicBounds(mMediaFileData.get(mPreviewPosition).isCheck ? R.mipmap.icon_preview_check : R.mipmap.icon_preview_uncheck, 0, 0, 0); + EventBus.getDefault().post(mMediaFileData.get(mPreviewPosition)); + if (mCheckAdapter != null) { + if (mMediaFileData.get(mPreviewPosition).isCheck) { + mCheckAdapter.addItemNotifyData(mMediaFileData.get(mPreviewPosition)); + mRvCheckMedia.scrollToPosition(mCheckMediaData.indexOf(mMediaFileData.get(mPreviewPosition))); + + } else { + if (mCheckMediaData.contains(mMediaFileData.get(mPreviewPosition))) { + mCheckAdapter.removeItemNotifyData(mCheckMediaData.indexOf(mMediaFileData.get(mPreviewPosition))); + mRvCheckMedia.scrollToPosition(mCheckMediaData.size() - 1); + } + } + } + //设置完成的数量 + setTitleViewSureText(); + } else { + Toasts.with().showToast(PreviewActivity.this, R.string.max_choose_media, String.valueOf(mOptions.maxChooseMedia)); + } + + + } + }); + mTvTop.setOnSureViewClickListener(new TitleView.OnSureViewClickListener() { + @Override + public void onSureClick(@NonNull View view) { + if (mCheckMediaData.size() <= 0) { + mMediaFileData.get(mPreviewPosition).isCheck = true; + mCheckMediaData.add(mMediaFileData.get(mPreviewPosition)); + } + sureData(); + + } + }); + } + + private void sureData() { + if (mOptions.isCompress && !mOptions.isShowVideo && !mOptions.isCrop) { + compressImage(mCheckMediaData, new CompressImageTask.OnImagesResult() { + @Override + public void startCompress() { + + } + + @Override + public void resultFilesSucceed(List list) { + mCheckMediaData.clear(); + for (int i = 0; i < list.size(); i++) { + mCheckMediaData.add(MediaSelectorFile.checkFileToThis(list.get(i))); + } + EventBus.getDefault().post(mCheckMediaData); + finish(); + } + + @Override + public void resultFilesError() { + + } + }); + } else { + if (mOptions.isCrop && mOptions.maxChooseMedia == 1) { + if (!mCheckMediaData.get(0).isVideo) { + UCrop.Options options = new UCrop.Options(); + options.setCompressionQuality(100); + options.setToolbarColor(ContextCompat.getColor(this, mOptions.themeColor)); + options.setStatusBarColor(ContextCompat.getColor(this, mOptions.themeColor)); + options.setLogoColor(ContextCompat.getColor(this, mOptions.themeColor)); + options.setActiveWidgetColor(ContextCompat.getColor(this, mOptions.themeColor)); + UCrop.of(Uri.fromFile(new File(mCheckMediaData.get(0).filePath)), Uri.fromFile(FileUtils.resultImageFile(this, "Crop"))) + .withAspectRatio(mOptions.scaleX, mOptions.scaleY) + .withMaxResultSize(mOptions.cropWidth, mOptions.cropHeight) + .withOptions(options) + .start(this); + } else { + Toasts.with().showToast(this, R.string.video_not_crop); + } + } else { + EventBus.getDefault().post(mCheckMediaData); + finish(); + } + } + } + + @Override + protected int getLayoutId() { + return R.layout.activity_preview; + } + + private void titleViewAnimation() { + ObjectAnimator topAnimatorTranslation; + ObjectAnimator bottomAnimatorTranslation; + if (mAnimatorSet == null) { + mAnimatorSet = new AnimatorSet(); + } + if (isShowTitleView) { + getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + mSystemBarTintManager.setStatusBarTintEnabled(false); + topAnimatorTranslation = ObjectAnimator.ofFloat(mTvTop, "translationY", 0, -(ScreenUtils.getStatuWindowsHeight(this) + mTvTop.getMeasuredHeight())); + bottomAnimatorTranslation = ObjectAnimator.ofFloat(mLlBottom, "translationY", 0, (mLlBottom.getMeasuredHeight())); + + } else { + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + mSystemBarTintManager.setStatusBarTintEnabled(true); + topAnimatorTranslation = ObjectAnimator.ofFloat(mTvTop, "translationY", -(ScreenUtils.getStatuWindowsHeight(this) + mTvTop.getMeasuredHeight()), 0); + bottomAnimatorTranslation = ObjectAnimator.ofFloat(mLlBottom, "translationY", (mLlBottom.getMeasuredHeight()), 0); + + } + mAnimatorSet.setDuration(500); + mAnimatorSet.setInterpolator(new LinearInterpolator()); + mAnimatorSet.playTogether(topAnimatorTranslation, bottomAnimatorTranslation); + mAnimatorSet.start(); + + + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + switch (resultCode) { + case 0: + if (requestCode == Contast.CODE_REQUEST_PRIVIEW_VIDEO && mPreviewAdapter.mCbPlay != null) { + mPreviewAdapter.mCbPlay.setChecked(false); + mPreviewAdapter.notifyDataSetChanged(); + } + case RESULT_OK: + if (requestCode == UCrop.REQUEST_CROP) { + if (data == null) { + return; + } + final Uri resultUri = UCrop.getOutput(data); + if (resultUri != null && resultUri.getPath() != null) { + mCheckMediaData.clear(); + File file = new File(resultUri.getPath()); + if (FileUtils.existsFile(file.getAbsolutePath())) { + mCheckMediaData.add(MediaSelectorFile.checkFileToThis(file)); + EventBus.getDefault().post(mCheckMediaData); + finish(); + } else { + Toasts.with().showToast(this, R.string.file_not_exit, Toast.LENGTH_SHORT); + } + } + + } + break; + case UCrop.RESULT_ERROR: + if (requestCode == UCrop.REQUEST_CROP) { + Toasts.with().showToast(this, R.string.crop_image_fail); + } + break; + default: + break; + } + } +} diff --git a/media/src/main/java/com/example/media/adapter/MediaCheckAdapter.java b/media/src/main/java/com/example/media/adapter/MediaCheckAdapter.java new file mode 100644 index 0000000..997fcb3 --- /dev/null +++ b/media/src/main/java/com/example/media/adapter/MediaCheckAdapter.java @@ -0,0 +1,98 @@ +package com.example.media.adapter; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import com.example.media.OnRecyclerItemClickListener; +import com.example.media.R; +import com.example.media.bean.MediaSelectorFile; +import com.example.media.utils.GlideUtils; + +import java.util.List; + +public class MediaCheckAdapter extends RecyclerView.Adapter { + private List mData; + private Context mContext; + private MediaSelectorFile mPreviewMedia; + + public void setOnRecyclerItemClickListener(OnRecyclerItemClickListener onRecyclerItemClickListener) { + this.onRecyclerItemClickListener = onRecyclerItemClickListener; + } + + private OnRecyclerItemClickListener onRecyclerItemClickListener; + + public MediaCheckAdapter(@NonNull Context context, @NonNull List data) { + this.mContext = context; + this.mData = data; + } + + public void notifyCheckData(MediaSelectorFile previewMedia) { + mPreviewMedia = previewMedia; + this.notifyDataSetChanged(); + } + + public void removeItemNotifyData(int position) { + mData.remove(position); + this.notifyDataSetChanged(); + } + + public void addItemNotifyData(@NonNull MediaSelectorFile previewMedia) { + mData.add(previewMedia); + this.notifyItemRemoved(mData.indexOf(previewMedia)); + } + + @NonNull + @Override + public MediaCheckAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { + return new ViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item_check_media_view, viewGroup, false)); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder viewHolder, final int i) { + viewHolder.mIvMediaType.setVisibility(mData.get(i).isVideo ? View.VISIBLE : View.GONE); + GlideUtils.loadImage(mContext, mData.get(i).filePath, viewHolder.mIvItem); + viewHolder.mIvItem.setBackgroundResource(mPreviewMedia.filePath.equals(mData.get(i).filePath) ? R.drawable.shape_media_check : R.drawable.shape_media_uncheck); + viewHolder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + if (onRecyclerItemClickListener != null) { + onRecyclerItemClickListener.itemClick(v, i); + } + /* if (!mPreviewMedia.filePath.equals(mData.get(i).filePath)) { + if (onRecyclerItemClickListener != null) { + onRecyclerItemClickListener.itemClick(v, i); + } + notifyDataSetChanged(); + }*/ + + } + }); + } + + @Override + public int getItemCount() { + return mData == null ? 0 : mData.size(); + } + + static class ViewHolder extends RecyclerView.ViewHolder { + + private ImageView mIvItem; + private ImageView mIvMediaType; + + ViewHolder(@NonNull View itemView) { + super(itemView); + initView(itemView); + } + + private void initView(View itemView) { + mIvItem = itemView.findViewById(R.id.iv_item); + mIvMediaType = itemView.findViewById(R.id.iv_media_type); + } + } +} diff --git a/media/src/main/java/com/example/media/adapter/MediaFileAdapter.java b/media/src/main/java/com/example/media/adapter/MediaFileAdapter.java new file mode 100644 index 0000000..a0009ee --- /dev/null +++ b/media/src/main/java/com/example/media/adapter/MediaFileAdapter.java @@ -0,0 +1,148 @@ +package com.example.media.adapter; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.example.item.util.ScreenUtils; +import com.example.media.MediaSelector; +import com.example.media.OnRecyclerItemClickListener; +import com.example.media.R; +import com.example.media.bean.MediaSelectorFile; +import com.example.media.resolver.Contast; +import com.example.media.utils.DateUtils; +import com.example.media.utils.GlideUtils; + +import java.util.List; + +public class MediaFileAdapter extends RecyclerView.Adapter { + private List mData; + private Context mContext; + private MediaSelector.MediaOptions mOptions; + + public void setOnCheckMediaListener(OnCheckMediaListener onCheckMediaListener) { + this.onCheckMediaListener = onCheckMediaListener; + } + + private OnCheckMediaListener onCheckMediaListener; + + public void setOnRecyclerItemClickListener(OnRecyclerItemClickListener onRecyclerItemClickListener) { + this.onRecyclerItemClickListener = onRecyclerItemClickListener; + } + + private OnRecyclerItemClickListener onRecyclerItemClickListener; + + public MediaFileAdapter(@NonNull Context context, @NonNull List data, @NonNull MediaSelector.MediaOptions options) { + this.mContext = context; + this.mData = data; + this.mOptions = options; + } + + + @NonNull + @Override + public MediaFileAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { + return new ViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item_media_file_view, viewGroup, false)); + } + + @Override + public void onBindViewHolder(@NonNull MediaFileAdapter.ViewHolder viewHolder, final int i) { + ViewGroup.LayoutParams layoutParams = viewHolder.mIvData.getLayoutParams(); + if (mData.get(i).isShowCamera) { + layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT; + layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT; + GlideUtils.loadImage(mContext, R.mipmap.icon_camera, viewHolder.mIvData); + viewHolder.mIvCheck.setVisibility(View.GONE); + viewHolder.mViewLay.setVisibility(View.GONE); + viewHolder.mRlVideo.setVisibility(View.GONE); + } else { + layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT; + layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT; + viewHolder.mIvCheck.setVisibility(mOptions.maxChooseMedia > 1 ? View.VISIBLE : View.GONE); + GlideUtils.loadImage(mContext, mData.get(i).filePath, viewHolder.mIvData); + viewHolder.mIvCheck.setImageResource(mData.get(i).isCheck ? R.mipmap.icon_image_checked : R.mipmap.icon_image_unchecked); + viewHolder.mViewLay.setVisibility(mData.get(i).isCheck ? View.VISIBLE : View.GONE); + + if (mData.get(i).isVideo) { + viewHolder.mRlVideo.setVisibility(View.VISIBLE); + viewHolder.mTvDuration.setText(DateUtils.videoDuration(mData.get(i).videoDuration)); + } else { + viewHolder.mRlVideo.setVisibility(View.GONE); + } + + + } + viewHolder.mIvData.setLayoutParams(layoutParams); + + viewHolder.mIvCheck.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (onCheckMediaListener != null) { + onCheckMediaListener.onChecked(mData.get(i).isCheck, i); + } + + } + }); + viewHolder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (onRecyclerItemClickListener != null) { + onRecyclerItemClickListener.itemClick(v, i); + } + } + }); + } + + @Override + public int getItemCount() { + return mData == null ? 0 : mData.size(); + } + + static class ViewHolder extends RecyclerView.ViewHolder { + + private ImageView mIvData; + private ImageView mIvCheck; + private View mViewLay; + private RelativeLayout mRlVideo; + private TextView mTvDuration; + + ViewHolder(@NonNull View itemView) { + super(itemView); + initView(itemView); + } + + private void initView(View itemView) { + ViewGroup mRootGroup = itemView.findViewById(R.id.rl_root); + mIvData = itemView.findViewById(R.id.iv_data); + mIvCheck = itemView.findViewById(R.id.iv_check); + mViewLay = itemView.findViewById(R.id.view_lay); + mRlVideo = itemView.findViewById(R.id.rl_video); + mTvDuration = itemView.findViewById(R.id.tv_duration); + MediaFileAdapter.setRootGroupParams(mRootGroup); + } + } + + + private static void setRootGroupParams(@NonNull ViewGroup viewGroup) { + ViewGroup.LayoutParams mGroupParams = viewGroup.getLayoutParams(); + mGroupParams.width = viewGroup.getContext().getResources().getDisplayMetrics().widthPixels / 4; + mGroupParams.height = viewGroup.getContext().getResources().getDisplayMetrics().widthPixels / 4; + viewGroup.setLayoutParams(mGroupParams); + viewGroup.setPadding(ScreenUtils.dp2px(viewGroup.getContext(), 1.5f), ScreenUtils.dp2px(viewGroup.getContext(), 1.5f), + ScreenUtils.dp2px(viewGroup.getContext(), 1.5f), ScreenUtils.dp2px(viewGroup.getContext(), 1.5f)); + } + + public interface OnCheckMediaListener { + void onChecked(boolean isCheck, int position); + } + +} diff --git a/media/src/main/java/com/example/media/adapter/MediaFolderAdapter.java b/media/src/main/java/com/example/media/adapter/MediaFolderAdapter.java new file mode 100644 index 0000000..190e94c --- /dev/null +++ b/media/src/main/java/com/example/media/adapter/MediaFolderAdapter.java @@ -0,0 +1,103 @@ +package com.example.media.adapter; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.example.media.OnRecyclerItemClickListener; +import com.example.media.R; +import com.example.media.bean.MediaSelectorFolder; +import com.example.media.utils.GlideUtils; + +import java.util.List; + +public class MediaFolderAdapter extends RecyclerView.Adapter { + private List mData; + + public void setOnRecyclerItemClickListener(OnRecyclerItemClickListener onRecyclerItemClickListener) { + this.onRecyclerItemClickListener = onRecyclerItemClickListener; + } + + private OnRecyclerItemClickListener onRecyclerItemClickListener; + + public MediaFolderAdapter(@Nullable List data) { + this.mData = data; + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { + return new ViewHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_media_folder, viewGroup, false)); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder viewHolder, final int i) { + if (mData.get(i).firstFilePath != null) { + GlideUtils.loadImage(viewHolder.itemView.getContext(), mData.get(i).firstFilePath, viewHolder.mIvLeft); + } + + viewHolder.mTvCount.setText(viewHolder.itemView.getContext().getString(R.string.how_match_open, String.valueOf(mData.get(i).fileData.size()))); + viewHolder.mTvTitle.setText(mData.get(i).folderName); + viewHolder.mIvCheck.setImageResource(mData.get(i).isCheck ? R.mipmap.icon_folder_check : R.mipmap.icon_folder_uncheck); + viewHolder.mIvVideoStype.setVisibility(mData.get(i).isAllVideo ? View.VISIBLE : View.GONE); + + viewHolder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + clickCheckSoleData(mData, i); + if (onRecyclerItemClickListener != null) { + onRecyclerItemClickListener.itemClick(v, i); + } + } + }); + } + + @Override + public int getItemCount() { + return mData == null ? 0 : mData.size(); + } + + static class ViewHolder extends RecyclerView.ViewHolder { + + private ImageView mIvLeft; + private TextView mTvTitle; + private TextView mTvCount; + private ImageView mIvCheck; + private ImageView mIvVideoStype; + + ViewHolder(@NonNull View itemView) { + super(itemView); + initView(itemView); + } + + private void initView(View itemView) { + mIvLeft = itemView.findViewById(R.id.iv_left); + mTvTitle = itemView.findViewById(R.id.tv_title); + mTvCount = itemView.findViewById(R.id.tv_count); + mIvCheck = itemView.findViewById(R.id.iv_check); + mIvVideoStype = itemView.findViewById(R.id.iv_video_type); + + } + } + + private void clickCheckSoleData(List data, int position) { + if (data != null && data.size() > position) { + if (!data.get(position).isCheck) { + for (int i = 0; i < data.size(); i++) { + if (i == position) { + mData.get(position).isCheck = true; + } else if (mData.get(i).isCheck) { + mData.get(i).isCheck = false; + } + } + notifyDataSetChanged(); + } + } + } +} diff --git a/media/src/main/java/com/example/media/adapter/PreviewAdapter.java b/media/src/main/java/com/example/media/adapter/PreviewAdapter.java new file mode 100644 index 0000000..f438109 --- /dev/null +++ b/media/src/main/java/com/example/media/adapter/PreviewAdapter.java @@ -0,0 +1,158 @@ +package com.example.media.adapter; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Color; +import android.media.MediaPlayer; +import android.net.Uri; +import android.support.annotation.NonNull; +import android.support.v4.view.PagerAdapter; +import android.support.v4.view.ViewPager; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.ImageView; +import android.widget.MediaController; +import android.widget.VideoView; + +import com.example.media.R; +import com.example.media.bean.MediaSelectorFile; +import com.example.media.utils.GlideUtils; +import com.example.media.utils.ScreenUtils; +import com.example.media.weight.Toasts; +import com.github.chrisbanes.photoview.OnPhotoTapListener; +import com.github.chrisbanes.photoview.PhotoView; + +import java.util.List; + +public class PreviewAdapter extends PagerAdapter { + + private int mChildCount; + private List mData; + public CheckBox mCbPlay; + + public void setOnPreviewViewClickListener(OnPreviewViewClickListener onPreviewViewClickListener) { + this.onPreviewViewClickListener = onPreviewViewClickListener; + } + + private OnPreviewViewClickListener onPreviewViewClickListener; + + public void setOnPreviewVideoClickListener(OnPreviewVideoClickListener onPreviewVideoClickListener) { + this.onPreviewVideoClickListener = onPreviewVideoClickListener; + } + + private OnPreviewVideoClickListener onPreviewVideoClickListener; + + public PreviewAdapter(List data) { + this.mData = data; + } + + @Override + public int getCount() { + return mData == null ? 0 : mData.size(); + } + + @Override + public boolean isViewFromObject(@NonNull View view, @NonNull Object o) { + return view == o; + } + + @Override + public void notifyDataSetChanged() { + mChildCount = getCount(); + super.notifyDataSetChanged(); + } + + @Override + public int getItemPosition(@NonNull Object object) { + if (mChildCount > 0) { + mChildCount--; + return PagerAdapter.POSITION_NONE; + } + return super.getItemPosition(object); + } + + @NonNull + @Override + public Object instantiateItem(@NonNull final ViewGroup container, final int position) { + if (mData.get(position).isVideo) { + View inflate = LayoutInflater.from(container.getContext()).inflate(R.layout.item_video_play_view, container, false); + container.addView(inflate); + + final PhotoView pTData = inflate.findViewById(R.id.pt_data); + mCbPlay = inflate.findViewById(R.id.cb_play); + ViewGroup.LayoutParams layoutParams = pTData.getLayoutParams(); + layoutParams.width = ScreenUtils.screenWidth(container.getContext()); + layoutParams.height = ScreenUtils.screenHeight(container.getContext()); + pTData.setLayoutParams(layoutParams); + GlideUtils.loadImage(container.getContext(), mData.get(position).filePath, pTData,false); + mCbPlay.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (isChecked && onPreviewVideoClickListener !=null) { + onPreviewVideoClickListener.onClickVideo(mCbPlay,position); + + } + } + }); + clickPhotoView(pTData); + + return inflate; + } else { + PhotoView photoView = new PhotoView(container.getContext()); + container.addView(photoView); + ViewGroup.LayoutParams layoutParams = photoView.getLayoutParams(); + layoutParams.width = ScreenUtils.screenWidth(container.getContext()); + layoutParams.height = ScreenUtils.screenHeight(container.getContext()); + photoView.setLayoutParams(layoutParams); + GlideUtils.loadImage(container.getContext(), mData.get(position).filePath, photoView,false); + clickPhotoView(photoView); + return photoView; + } + + } + + private void clickPhotoView(@NonNull PhotoView photoView) { + photoView.setOnPhotoTapListener(new OnPhotoTapListener() { + @Override + public void onPhotoTap(ImageView view, float x, float y) { + if (onPreviewViewClickListener != null) { + onPreviewViewClickListener.onPreviewView(view); + } + } + }); + } + + + @Override + public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { + container.removeView((View) object); + } + + public static class PreviewPageTransformer implements ViewPager.PageTransformer { + private ViewPager viewPager; + + @Override + public void transformPage(@NonNull View view, float position) { + if (viewPager == null) { + viewPager = (ViewPager) view.getParent(); + } + int leftInScreen = view.getLeft() - viewPager.getScrollX(); + float offsetRate = (float) leftInScreen * 0.08f / viewPager.getMeasuredWidth(); + float scaleFactor = 1 - Math.abs(offsetRate); + if (scaleFactor > 0) { + view.setScaleX(scaleFactor); + } + } + } + + public interface OnPreviewViewClickListener { + void onPreviewView(View view); + } + + public interface OnPreviewVideoClickListener { + void onClickVideo(View view, int position); + } +} diff --git a/media/src/main/java/com/example/media/bean/MediaSelectorFile.java b/media/src/main/java/com/example/media/bean/MediaSelectorFile.java new file mode 100644 index 0000000..7e96d5a --- /dev/null +++ b/media/src/main/java/com/example/media/bean/MediaSelectorFile.java @@ -0,0 +1,114 @@ +package com.example.media.bean; + +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.NonNull; +import android.text.TextUtils; + +import com.example.media.utils.FileUtils; + +import java.io.File; + +import utils.bean.ImageConfig; + +public class MediaSelectorFile implements Parcelable { + public String fileName; + public String filePath; + public int fileSize; + public int width; + public int height; + public String folderName; + public String folderPath; + public boolean isCheck; + public boolean isShowCamera; + public boolean isVideo; + public long videoDuration; + + public MediaSelectorFile() { + } + + protected MediaSelectorFile(Parcel in) { + fileName = in.readString(); + filePath = in.readString(); + fileSize = in.readInt(); + width = in.readInt(); + height = in.readInt(); + folderName = in.readString(); + folderPath = in.readString(); + isCheck = in.readByte() != 0; + isShowCamera = in.readByte() != 0; + isVideo = in.readByte() != 0; + videoDuration = in.readLong(); + } + + public static final Creator CREATOR = new Creator() { + @Override + public MediaSelectorFile createFromParcel(Parcel in) { + return new MediaSelectorFile(in); + } + + @Override + public MediaSelectorFile[] newArray(int size) { + return new MediaSelectorFile[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(fileName); + dest.writeString(filePath); + dest.writeInt(fileSize); + dest.writeInt(width); + dest.writeInt(height); + dest.writeString(folderName); + dest.writeString(folderPath); + dest.writeByte((byte) (isCheck ? 1 : 0)); + dest.writeByte((byte) (isShowCamera ? 1 : 0)); + dest.writeByte((byte) (isVideo ? 1 : 0)); + dest.writeLong(videoDuration); + } + + @Override + public boolean equals(Object obj) { + if (obj != null && obj instanceof MediaSelectorFile) { + MediaSelectorFile mediaSelectorFile = (MediaSelectorFile) obj; + if (mediaSelectorFile.filePath != null && this.filePath != null && + mediaSelectorFile.filePath.equals(filePath)) { + return true; + } + } + return super.equals(obj); + } + + + public boolean hasData() { + return !TextUtils.isEmpty(fileName) && TextUtils.getTrimmedLength(fileName) > 0 + && !TextUtils.isEmpty(filePath) && TextUtils.getTrimmedLength(filePath) > 0 + && fileSize > 0 && width > 0 && height > 0 + && !TextUtils.isEmpty(folderName) && TextUtils.getTrimmedLength(folderName) > 0 + && !TextUtils.isEmpty(folderPath) && TextUtils.getTrimmedLength(folderPath) > 0; + } + + public static MediaSelectorFile checkFileToThis(@NonNull File file) { + MediaSelectorFile mediaFile = new MediaSelectorFile(); + mediaFile.fileName = file.getName(); + mediaFile.filePath = file.getAbsolutePath(); + mediaFile.fileSize = (int) file.length(); + mediaFile.width = FileUtils.getFileWidth(file.getAbsolutePath()); + mediaFile.height = FileUtils.getFileHeight(file.getAbsolutePath()); + mediaFile.folderName = FileUtils.getParentFileName(file.getAbsolutePath()); + mediaFile.folderPath = FileUtils.getParentFilePath(file.getAbsolutePath()); + mediaFile.isCheck = true; + return mediaFile; + } + + public static ImageConfig thisToDefaultImageConfig(@NonNull MediaSelectorFile mediaFile) { + return ImageConfig.getDefaultConfig(mediaFile.filePath); + } + +} diff --git a/media/src/main/java/com/example/media/bean/MediaSelectorFolder.java b/media/src/main/java/com/example/media/bean/MediaSelectorFolder.java new file mode 100644 index 0000000..c61c766 --- /dev/null +++ b/media/src/main/java/com/example/media/bean/MediaSelectorFolder.java @@ -0,0 +1,75 @@ +package com.example.media.bean; + +import android.os.Parcel; +import android.os.Parcelable; +import android.support.v4.util.LruCache; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +public class MediaSelectorFolder implements Parcelable { + public String folderName; + public String folderPath; + public List fileData = new ArrayList<>(); + public boolean isCheck; + public String firstFilePath; + public boolean isAllVideo; + + public MediaSelectorFolder() { + } + + protected MediaSelectorFolder(Parcel in) { + folderName = in.readString(); + folderPath = in.readString(); + fileData = in.createTypedArrayList(MediaSelectorFile.CREATOR); + isCheck = in.readByte() != 0; + firstFilePath = in.readString(); + isAllVideo = in.readByte() != 0; + } + + public static final Creator CREATOR = new Creator() { + @Override + public MediaSelectorFolder createFromParcel(Parcel in) { + return new MediaSelectorFolder(in); + } + + @Override + public MediaSelectorFolder[] newArray(int size) { + return new MediaSelectorFolder[size]; + } + }; + + /** + * 判断文件夹的路径是否一致判断是否相等 + * + * @param obj + * @return + */ + @Override + public boolean equals(Object obj) { + if (obj == null || folderPath == null) + return false; + if (obj instanceof MediaSelectorFolder) { + MediaSelectorFolder folder = (MediaSelectorFolder) obj; + return this.folderPath.equals(folder.folderPath); + } + return super.equals(obj); + } + + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(folderName); + dest.writeString(folderPath); + dest.writeTypedList(fileData); + dest.writeByte((byte) (isCheck ? 1 : 0)); + dest.writeString(firstFilePath); + dest.writeByte((byte) (isAllVideo ? 1 : 0)); + } +} diff --git a/media/src/main/java/com/example/media/permission/IntentUtils.java b/media/src/main/java/com/example/media/permission/IntentUtils.java new file mode 100644 index 0000000..572c936 --- /dev/null +++ b/media/src/main/java/com/example/media/permission/IntentUtils.java @@ -0,0 +1,46 @@ +package com.example.media.permission; + +import android.app.Activity; +import android.content.Intent; +import android.net.Uri; +import android.provider.Settings; +import android.support.annotation.NonNull; +import android.support.v4.app.Fragment; + +/** + * 项 目 : YZBProject + * 包 名 : com.henji.yunyi.yizhibang.utils + * 类 名 : IntentUtils + * 作 者 : 胡庆岭 + * 时 间 : 2018/1/9 0009 下午 4:03 + * 描 述 : ${TODO}意图工具类 + * + * @author : + */ + +public class IntentUtils { + public static final int OPEN_APPLY_CENTER_CODE = 5501; + + /** + * Activity打开应用中心 + * + * @param activity 页面 + */ + public static void openActivityApplyCenter(@NonNull Activity activity) { + Uri packageURI = Uri.parse("package:" + activity.getPackageName()); + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, packageURI); + activity.startActivityForResult(intent, OPEN_APPLY_CENTER_CODE); + } + + /** + * fragemnt打开应用中心 + * + * @param fragment fragment + * @param activity activity + */ + public static void openFragmentApplyCenter(@NonNull Fragment fragment, @NonNull Activity activity) { + Uri packageURI = Uri.parse("package:" + activity.getPackageName()); + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, packageURI); + fragment.startActivityForResult(intent, OPEN_APPLY_CENTER_CODE); + } +} diff --git a/media/src/main/java/com/example/media/permission/PermissionActivity.java b/media/src/main/java/com/example/media/permission/PermissionActivity.java new file mode 100644 index 0000000..86892df --- /dev/null +++ b/media/src/main/java/com/example/media/permission/PermissionActivity.java @@ -0,0 +1,189 @@ +package com.example.media.permission; + +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.ActivityCompat; +import android.support.v7.app.AlertDialog; +import android.support.v7.app.AppCompatActivity; +import android.util.Log; +import android.view.View; +import android.widget.Button; + + +import com.example.media.permission.imp.OnPermissionsResult; +import com.trello.rxlifecycle2.components.support.RxAppCompatActivity; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * 项 目 : PermissionUtils + * 包 名 : com.baixiaohu.permissionutils + * 类 名 : PermissionActivity + * 作 者 : 胡庆岭 + * 时 间 : 2018/1/11 0011 下午 12:05 + * 描 述 : ${TODO} + * + * @author : + */ + +public class PermissionActivity extends RxAppCompatActivity { + private AlertDialog mForbidDialog; + private static final int REQUEST_CODE = 100; + private List mAllowList = new ArrayList<>(); + private List mNoAllowList = new ArrayList<>(); + private List mForbidList = new ArrayList<>(); + private OnPermissionsResult mOnPermissionsResult; + private String[] mPermissions; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + + protected void requestPermission(@NonNull OnPermissionsResult onPermissionsResult, @NonNull String... permissions) { + this.mPermissions = permissions; + this.mOnPermissionsResult = onPermissionsResult; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + List requestList = new ArrayList<>(); + for (String permission : permissions) { + if (ActivityCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) { + requestList.add(permission); + } + } + if (requestList.size() > 0) { + ActivityCompat.requestPermissions(this, permissions, REQUEST_CODE); + } else { + if (mOnPermissionsResult != null ) { + mOnPermissionsResult.onAllow(Arrays.asList(permissions)); + } + } + } else { + mOnPermissionsResult.onAllow(Arrays.asList(permissions)); + } + + + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + switch (requestCode) { + case REQUEST_CODE: + if (permissions.length == grantResults.length) { + clearPermission(); + + for (int i = 0; i < grantResults.length; i++) { + + if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { + mAllowList.add(permissions[i]); + } else { + Log.w("onRequemt--", ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[i]) + ""); + if (ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[i])) { + mNoAllowList.add(permissions[i]); + } else { + mForbidList.add(permissions[i]); + } + } + } + Log.w("onRequest--", permissions.length + "--" + grantResults.length + + "--" + mAllowList.size() + "--" + mNoAllowList.size() + "--" + mForbidList.size()); + if (mAllowList.size() == permissions.length) { + if (mOnPermissionsResult != null) { + //全部同意 + mOnPermissionsResult.onAllow(mAllowList); + } + + } else { + if (mForbidList.size() > 0) { + if (mOnPermissionsResult != null) { + //全部永久禁止或者部分永久禁止 + mOnPermissionsResult.onForbid(mForbidList); + } + } else { + if (mOnPermissionsResult != null) { + //全部拒绝 + mOnPermissionsResult.onNoAllow(mNoAllowList); + } + } + } + + } + break; + default: + break; + } + } + + private void clearPermission() { + mAllowList.clear(); + mNoAllowList.clear(); + mForbidList.clear(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + clearPermission(); + } + + protected void showForbidPermissionDialog() { + if (mForbidDialog == null) { + mForbidDialog = new AlertDialog.Builder(this).setTitle("权限被禁止") + .setMessage("需要获取权限,否则无法正常使用功能;设置路径:设置-应用-权限") + .setPositiveButton("确定", null) + .setNegativeButton("取消", null) + .setCancelable(false).create(); + mForbidDialog.setOnShowListener(new DialogInterface.OnShowListener() { + @Override + public void onShow(DialogInterface dialog) { + Button positionButton = mForbidDialog.getButton(AlertDialog.BUTTON_POSITIVE); + Button negativeButton = mForbidDialog.getButton(AlertDialog.BUTTON_NEGATIVE); + positionButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + IntentUtils.openActivityApplyCenter(PermissionActivity.this); + + } + }); + negativeButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + mForbidDialog.dismiss(); + finish(); + } + }); + + } + }); + mForbidDialog.show(); + } else if (!mForbidDialog.isShowing()) { + mForbidDialog.show(); + } + } + + protected void dismissForbidPermissionDialog() { + if (mForbidDialog != null && mForbidDialog.isShowing()) { + mForbidDialog.dismiss(); + } + } + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == IntentUtils.OPEN_APPLY_CENTER_CODE && resultCode == 0) { + if (mPermissions != null && mPermissions.length > 0 && mOnPermissionsResult != null) { + requestPermission(mOnPermissionsResult, mPermissions); + dismissForbidPermissionDialog(); + // getActivity().recreate(); + } + } + } +} diff --git a/media/src/main/java/com/example/media/permission/PermissionFragment.java b/media/src/main/java/com/example/media/permission/PermissionFragment.java new file mode 100644 index 0000000..76044d8 --- /dev/null +++ b/media/src/main/java/com/example/media/permission/PermissionFragment.java @@ -0,0 +1,185 @@ +package com.example.media.permission; + +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Build; +import android.support.annotation.NonNull; +import android.support.v4.app.ActivityCompat; +import android.support.v4.app.Fragment; +import android.support.v7.app.AlertDialog; +import android.util.Log; +import android.view.View; +import android.widget.Button; + + +import com.example.media.permission.imp.OnPermissionsResult; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * 项 目 : PermissionUtils + * 包 名 : com.baixiaohu.permission + * 类 名 : PermissionFragment + * 作 者 : 胡庆岭 + * 时 间 : 2018/1/15 0015 上午 9:51 + * 描 述 : ${TODO} + * + * @author : + */ + +public class PermissionFragment extends Fragment { + private static final int REQUEST_CODE = 200; + private static List mAllowList = new ArrayList<>(); + private static List mNoAllowList = new ArrayList<>(); + private static List mForbidList = new ArrayList<>(); + private OnPermissionsResult mOnPermissionsResult; + private AlertDialog mForbidDialog; + private String[] mPermissions; + + @Override + public void onResume() { + super.onResume(); + } + + protected void requestPermission(@NonNull OnPermissionsResult onPermissionsResult, @NonNull String... permissions) { + this.mPermissions = permissions; + this.mOnPermissionsResult = onPermissionsResult; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + List requestList = new ArrayList<>(); + for (String permission : permissions) { + if (ActivityCompat.checkSelfPermission(getActivity(), permission) != PackageManager.PERMISSION_GRANTED) { + requestList.add(permission); + } + } + if (requestList.size() > 0) { + this.requestPermissions(permissions, REQUEST_CODE); + } else { + if (mOnPermissionsResult != null) { + mOnPermissionsResult.onAllow(Arrays.asList(permissions)); + } + } + } else { + mOnPermissionsResult.onAllow(Arrays.asList(permissions)); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + switch (requestCode) { + case REQUEST_CODE: + if (permissions.length == grantResults.length) { + clearPermission(); + for (int i = 0; i < grantResults.length; i++) { + + if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { + mAllowList.add(permissions[i]); + } else { + Log.w("onRequemt--", ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), permissions[i]) + ""); + if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), permissions[i])) { + mNoAllowList.add(permissions[i]); + } else { + mForbidList.add(permissions[i]); + } + } + } + Log.w("onRequest--", permissions.length + "--" + grantResults.length + + "--" + mAllowList.size() + "--" + mNoAllowList.size() + "--" + mForbidList.size()); + if (mAllowList.size() == permissions.length) { + if (mOnPermissionsResult != null) { + //全部同意 + mOnPermissionsResult.onAllow(mAllowList); + } + + } else { + if (mForbidList.size() > 0) { + if (mOnPermissionsResult != null) { + //全部永久禁止或者部分永久禁止 + mOnPermissionsResult.onForbid(mForbidList); + } + } else { + if (mOnPermissionsResult != null) { + //全部拒绝 + mOnPermissionsResult.onNoAllow(mNoAllowList); + } + } + } + } + break; + default: + break; + } + } + + private void clearPermission() { + mAllowList.clear(); + mNoAllowList.clear(); + mForbidList.clear(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + clearPermission(); + } + + protected void showForbidPermissionDialog() { + if (mForbidDialog == null) { + mForbidDialog = new AlertDialog.Builder(getActivity()).setTitle( "权限被禁止") + .setMessage("需要获取权限,否则无法正常使用功能;设置路径:设置-应用-权限") + .setPositiveButton("确定", null) + .setNegativeButton("取消", null) + .setCancelable(false).create(); + mForbidDialog.setOnShowListener(new DialogInterface.OnShowListener() { + @Override + public void onShow(DialogInterface dialog) { + Button positionButton = mForbidDialog.getButton(AlertDialog.BUTTON_POSITIVE); + Button negativeButton = mForbidDialog.getButton(AlertDialog.BUTTON_NEGATIVE); + positionButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + IntentUtils.openFragmentApplyCenter(PermissionFragment.this, getActivity()); + + } + }); + negativeButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + mForbidDialog.dismiss(); + getActivity().finish(); + } + }); + + } + }); + mForbidDialog.show(); + } else if (!mForbidDialog.isShowing()) { + mForbidDialog.show(); + } + + } + + + protected void dismissForbidPermissionDialog() { + if (mForbidDialog != null && mForbidDialog.isShowing()) { + mForbidDialog.dismiss(); + } + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + Log.w("FragmentResult--", requestCode + "--" + resultCode); + if (requestCode == IntentUtils.OPEN_APPLY_CENTER_CODE && resultCode == 0) { + if (mPermissions != null && mPermissions.length > 0 && mOnPermissionsResult != null) { + requestPermission(mOnPermissionsResult, mPermissions); + dismissForbidPermissionDialog(); + // getActivity().recreate(); + } + } + } +} diff --git a/media/src/main/java/com/example/media/permission/imp/OnPermissionsResult.java b/media/src/main/java/com/example/media/permission/imp/OnPermissionsResult.java new file mode 100644 index 0000000..d8db02a --- /dev/null +++ b/media/src/main/java/com/example/media/permission/imp/OnPermissionsResult.java @@ -0,0 +1,23 @@ +package com.example.media.permission.imp; + +import java.util.List; + +/** + * 项 目 : PermissionUtils + * 包 名 : com.baixiaohu.permission.imp + * 类 名 : OnPermissionsResult + * 作 者 : 胡庆岭 + * 时 间 : 2018/1/11 0011 下午 3:07 + * 描 述 : ${TODO} + * + * @author : + */ + +public interface OnPermissionsResult { + void onAllow(List allowPermissions); + + void onNoAllow(List noAllowPermissions); + + void onForbid(List noForbidPermissions); + +} diff --git a/media/src/main/java/com/example/media/provider/MediaProvider.java b/media/src/main/java/com/example/media/provider/MediaProvider.java new file mode 100644 index 0000000..589fc0e --- /dev/null +++ b/media/src/main/java/com/example/media/provider/MediaProvider.java @@ -0,0 +1,17 @@ +package com.example.media.provider; + +import android.support.v4.content.FileProvider; + +/** + * 项 目 : ImageCompress + * 包 名 : com.baixiaohu.imagecompress.provider + * 类 名 : MediaProvider + * 作 者 : 胡小白 + * 时 间 : 2018/1/31 0031 上午 10:33 + * 描 述 : ${TODO} + * + * @author : + */ + +public class MediaProvider extends FileProvider { +} diff --git a/media/src/main/java/com/example/media/resolver/ActivityManger.java b/media/src/main/java/com/example/media/resolver/ActivityManger.java new file mode 100644 index 0000000..4cf0c23 --- /dev/null +++ b/media/src/main/java/com/example/media/resolver/ActivityManger.java @@ -0,0 +1,60 @@ +package com.example.media.resolver; + +import android.app.Activity; +import android.support.annotation.NonNull; +import android.support.v4.util.SparseArrayCompat; + +import java.lang.ref.SoftReference; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +public class ActivityManger { + private static ActivityManger mManger; + private Map> mMap; + + private ActivityManger() { + mMap = new HashMap<>(); + } + + public static ActivityManger get() { + synchronized (ActivityManger.class) { + if (mManger == null) { + synchronized (ActivityManger.class) { + mManger = new ActivityManger(); + } + } + } + return mManger; + } + + public void addActivity(@NonNull Activity activity) { + mMap.put(activity.getClass().getSimpleName(), new SoftReference<>(activity)); + } + + public void removeActivity(@NonNull String key) { + if (mMap.size() > 0) { + SoftReference softReference = mMap.get(key); + if (softReference != null && softReference.get() != null && !softReference.get().isFinishing()) { + softReference.get().finish(); + } + mMap.remove(key); + } + } + + public void clearActivity() { + if (mMap.size() > 0) { + Set>> entrySet = mMap.entrySet(); + Iterator>> iterator = entrySet.iterator(); + while (iterator.hasNext()) { + Map.Entry> next = iterator.next(); + if (next.getValue() != null && next.getValue().get() != null) { + next.getValue().get().finish(); + } + iterator.remove(); + } + } + } + +} diff --git a/media/src/main/java/com/example/media/resolver/Contast.java b/media/src/main/java/com/example/media/resolver/Contast.java new file mode 100644 index 0000000..a7009a1 --- /dev/null +++ b/media/src/main/java/com/example/media/resolver/Contast.java @@ -0,0 +1,21 @@ +package com.example.media.resolver; + +public interface Contast { + String KEY_PREVIEW_DATA_MEDIA = "key_preview_data_media"; + String KEY_PREVIEW_CHECK_MEDIA = "key_preview_check_media"; + String KEY_PREVIEW_POSITION = "key_preview_position"; + String KEY_CLEAR_MEDIA_DATA = "key_clear_media_data"; + int REQUEST_CODE_MEDIA_TO_PREVIEW = 101; + int MAX_CHOOSE_MEDIA = 9; + String KEY_OPEN_MEDIA = "key_open_media"; + + String KEY_REQUEST_MEDIA_DATA = "key_request_media_data"; + int CODE_REQUEST_MEDIA = 1011; + int CODE_RESULT_MEDIA = 1012; + int CODE_REQUEST_PRIVIEW_VIDEO = 1013; + String ALL_FILE = "全部文件"; + String ALL_VIDEO = "全部视频"; + int REQUEST_CAMERA_CODE = 2000; + + +} diff --git a/media/src/main/java/com/example/media/resolver/ILoadMediaResult.java b/media/src/main/java/com/example/media/resolver/ILoadMediaResult.java new file mode 100644 index 0000000..e1b9b36 --- /dev/null +++ b/media/src/main/java/com/example/media/resolver/ILoadMediaResult.java @@ -0,0 +1,9 @@ +package com.example.media.resolver; + +import com.example.media.bean.MediaSelectorFolder; + +import java.util.List; + +public interface ILoadMediaResult { + void mediaResult(List data); +} diff --git a/media/src/main/java/com/example/media/resolver/MediaHelper.java b/media/src/main/java/com/example/media/resolver/MediaHelper.java new file mode 100644 index 0000000..123118a --- /dev/null +++ b/media/src/main/java/com/example/media/resolver/MediaHelper.java @@ -0,0 +1,148 @@ +package com.example.media.resolver; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.database.Cursor; +import android.net.Uri; +import android.os.Build; +import android.provider.MediaStore; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.TextUtils; +import android.util.Log; +import android.widget.Toast; + +import com.example.media.bean.MediaSelectorFile; +import com.example.media.bean.MediaSelectorFolder; +import com.example.media.utils.FileUtils; + +import java.util.ArrayList; +import java.util.List; + +public class MediaHelper { + private static final Uri QUERY_URI = MediaStore.Files.getContentUri("external"); + //查询的内容 + @SuppressLint("InlinedApi") + private static final String[] IMAGE_PROJECTION = { + MediaStore.Files.FileColumns._ID, + MediaStore.Files.FileColumns.DATA, + MediaStore.Files.FileColumns.WIDTH, + MediaStore.Files.FileColumns.HEIGHT, + MediaStore.Files.FileColumns.SIZE, + MediaStore.Files.FileColumns.MEDIA_TYPE, + MediaStore.Files.FileColumns.DISPLAY_NAME}; + @SuppressLint("InlinedApi") + private static final String[] ALL_PROJECTION = { + MediaStore.Files.FileColumns._ID, + MediaStore.Files.FileColumns.DATA, + MediaStore.Files.FileColumns.WIDTH, + MediaStore.Files.FileColumns.HEIGHT, + MediaStore.Files.FileColumns.SIZE, + MediaStore.Files.FileColumns.MEDIA_TYPE, + MediaStore.Files.FileColumns.DISPLAY_NAME, + MediaStore.Video.Media.DURATION}; + private static final String IMAGE_SELECTION_TYPE = MediaStore.Files.FileColumns.MEDIA_TYPE + "=?" + " AND " + MediaStore.MediaColumns.SIZE + ">0"; + private static final String ALL_SELECTION_TYPE = "(" + MediaStore.Files.FileColumns.MEDIA_TYPE + "=? OR " + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?)" + + " AND " + MediaStore.MediaColumns.SIZE + ">0"; + private static final String[] IMAGE_WHERE_TYPE = new String[]{String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE)}; + private static final String[] ALL_WHERE_TYPE = new String[]{String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE), String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO)}; + private static final String SORT_ORDER = MediaStore.Files.FileColumns.DATE_MODIFIED + " desc"; + private Activity mActivity; + + public MediaHelper(@NonNull Activity activity) { + this.mActivity = activity; + } + + + public void loadMedia(boolean isShowCamera, boolean isShowVideo, @Nullable ILoadMediaResult onResult) { + + Cursor cursor = mActivity.getContentResolver().query(MediaHelper.QUERY_URI, isShowVideo ? ALL_PROJECTION : MediaHelper.IMAGE_PROJECTION, isShowVideo ? ALL_SELECTION_TYPE : MediaHelper.IMAGE_SELECTION_TYPE, isShowVideo ? ALL_WHERE_TYPE : MediaHelper.IMAGE_WHERE_TYPE, SORT_ORDER); + if (cursor != null && !cursor.isClosed() && cursor.getCount() > 0) { + //所有的图片 + List mAllFileData = new ArrayList<>(); + + //所有文件夹 + List folderData = new ArrayList<>(); + List mVideoFileData = new ArrayList<>(); + + while (cursor.moveToNext()) { + MediaSelectorFile mediaFile = new MediaSelectorFile(); + mediaFile.fileName = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DISPLAY_NAME)); + + mediaFile.filePath = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DATA)); + if (TextUtils.isEmpty(mediaFile.fileName) || TextUtils.isEmpty(mediaFile.filePath) + || TextUtils.getTrimmedLength(mediaFile.fileName) == 0 || TextUtils.getTrimmedLength(mediaFile.filePath) == 0 || mediaFile.fileName.endsWith(".gif")) { + continue; + } + mediaFile.fileSize = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.SIZE)); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + mediaFile.width = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.WIDTH)); + mediaFile.height = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.HEIGHT)); + } + if (FileUtils.existsFile(mediaFile.filePath)) { + mediaFile.folderName = FileUtils.getParentFileName(mediaFile.filePath); + mediaFile.folderPath = FileUtils.getParentFilePath(mediaFile.filePath); + } else { + continue; + } + mediaFile.isVideo = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.MEDIA_TYPE)) == MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO; + if (mediaFile.isVideo) { + mediaFile.videoDuration = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION)); + if (mediaFile.videoDuration >= 60 * 60 * 1000 || mediaFile.videoDuration < 1000) { + continue; + } + mVideoFileData.add(mediaFile); + } + + MediaSelectorFolder mediaFolder = new MediaSelectorFolder(); + mediaFolder.folderPath = mediaFile.folderPath; + //首先判断该文件的父文件夹有没有在集合中?有的话直接把文件加入对应的文件夹:没有就新建一个文件夹再添加进去 + if (folderData.size() > 0 && folderData.contains(mediaFolder) && folderData.indexOf(mediaFolder) >= 0) { + folderData.get(folderData.indexOf(mediaFolder)).fileData.add(mediaFile); + } else { + mediaFolder.folderName = mediaFile.folderName; + mediaFolder.fileData.add(mediaFile); + mediaFolder.firstFilePath = mediaFile.filePath; + folderData.add(mediaFolder); + } + mAllFileData.add(mediaFile); + + } + cursor.close(); + if (mAllFileData.size() > 0) { + if (isShowCamera) { + MediaSelectorFile cameraMediaFile = new MediaSelectorFile(); + cameraMediaFile.isShowCamera = true; + mAllFileData.add(0, cameraMediaFile); + } + + MediaSelectorFolder allMediaFolder = new MediaSelectorFolder(); + allMediaFolder.folderPath = Contast.ALL_FILE; + allMediaFolder.folderName = Contast.ALL_FILE; + allMediaFolder.firstFilePath = isShowCamera ? mAllFileData.get(1).filePath : mAllFileData.get(0).filePath; + allMediaFolder.fileData.addAll(mAllFileData); + allMediaFolder.isCheck = true; + folderData.add(0, allMediaFolder); + //增加视频目录 + if (mVideoFileData.size() > 0) { + MediaSelectorFolder videoMediaFolder = new MediaSelectorFolder(); + videoMediaFolder.folderPath = Contast.ALL_VIDEO; + videoMediaFolder.folderName = Contast.ALL_VIDEO; + videoMediaFolder.firstFilePath = mVideoFileData.get(0).filePath; + videoMediaFolder.fileData.addAll(mVideoFileData); + videoMediaFolder.isAllVideo = true; + folderData.add(folderData.indexOf(allMediaFolder) + 1, videoMediaFolder); + } + if (onResult != null && folderData.size() > 0) { + onResult.mediaResult(folderData); + } + } + + } else { + Toast.makeText(mActivity, "没有文件", Toast.LENGTH_SHORT).show(); + } + + } + + +} diff --git a/media/src/main/java/com/example/media/utils/DateUtils.java b/media/src/main/java/com/example/media/utils/DateUtils.java new file mode 100644 index 0000000..06e833c --- /dev/null +++ b/media/src/main/java/com/example/media/utils/DateUtils.java @@ -0,0 +1,26 @@ +package com.example.media.utils; + +public class DateUtils { + public static String videoDuration(long videoDuration) { + StringBuilder sb = new StringBuilder(); + if (videoDuration >= 1000) { + int second = (int) (videoDuration / 1000); + if (second / 60 >= 1) { + int minute = second / 60; + int remainderSecond = second % 60; + sb.append(minute).append(remainderSecond >= 10 ? ":" + remainderSecond : ":0" + remainderSecond); + } else { + if (second >= 10) { + sb.append("0:").append(second); + } else { + sb.append("0:0").append(second); + } + } + + } else { + sb.append("0:01"); + } + return sb.toString(); + + } +} diff --git a/media/src/main/java/com/example/media/utils/FileUtils.java b/media/src/main/java/com/example/media/utils/FileUtils.java new file mode 100644 index 0000000..1afbb69 --- /dev/null +++ b/media/src/main/java/com/example/media/utils/FileUtils.java @@ -0,0 +1,140 @@ +package com.example.media.utils; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.os.Build; +import android.os.Environment; +import android.support.annotation.NonNull; +import android.support.v4.content.FileProvider; + +import com.example.media.weight.MediaScanner; + +import java.io.File; +import java.util.List; + +/** + * 文件工具类 + */ +public class FileUtils { + + public static final String FILE_DIRECTOR_NAME = "MediaSelector"; + + /** + * 获取父文件夹名字 + * + * @param filePath + * @return + * @throws Exception + */ + public static String getParentFileName(@NonNull String filePath) { + return getParentFile(filePath).getName(); + } + + /** + * 获取父文件夹绝对路径 + * + * @param filePath + * @return + * @throws Exception + */ + public static String getParentFilePath(@NonNull String filePath) { + return getParentFile(filePath).getAbsolutePath(); + } + + private static File getParentFile(@NonNull String filePath) { + File file = new File(filePath); + if (file.exists() && file.isFile()) { + return file.getParentFile(); + } + throw new NullPointerException("file must exists or isFile"); + } + + public static boolean existsFile(@NonNull String filePath) { + File file = new File(filePath); + if (file.exists() && file.isFile()) + return true; + return false; + } + + public static File outCameraFileDirectory(Context context) { + String storageState = Environment.getExternalStorageState(); + File rootFile = storageState.equals(Environment.MEDIA_MOUNTED) ? Environment.getExternalStorageDirectory() : context.getCacheDir(); + rootFile = new File(rootFile.getAbsolutePath(), FILE_DIRECTOR_NAME.concat("/Camera")); + if (!rootFile.exists() || !rootFile.isDirectory()) { + rootFile.mkdirs(); + } + return rootFile; + } + + + public static File outFileDirectory(Context context, String folderName) { + String storageState = Environment.getExternalStorageState(); + File rootFile = storageState.equals(Environment.MEDIA_MOUNTED) ? Environment.getExternalStorageDirectory() : context.getCacheDir(); + rootFile = new File(rootFile.getAbsolutePath(), FILE_DIRECTOR_NAME.concat("/").concat(folderName)); + if (!rootFile.exists() || !rootFile.isDirectory()) { + rootFile.mkdirs(); + } + return rootFile; + } + + public static File resultImageFile(Context context) { + return new File(outCameraFileDirectory(context).getAbsolutePath(), "hxb" + System.currentTimeMillis() + ".jpg"); + } + + public static File resultImageFile(Context context, String folderName) { + return new File(outFileDirectory(context, folderName).getAbsolutePath(), "crop" + System.currentTimeMillis() + ".jpg"); + } + + public static Uri fileToUri(@NonNull Context context, @NonNull File file, @NonNull Intent intent) { + Uri uri; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + String authority = context.getPackageName() + ".provider"; + uri = FileProvider.getUriForFile(context, authority, file); + List resolveInfoData = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); + if (resolveInfoData != null && resolveInfoData.size() > 0) + for (ResolveInfo resolveInfo : resolveInfoData) { + String packageName = resolveInfo.activityInfo.packageName; + context.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + } + } else { + uri = Uri.fromFile(file); + } + return uri; + } + + public static void scanImage(@NonNull Context context, @NonNull File file) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + MediaScanner ms = new MediaScanner(context, file); + ms.refresh(); + } else { + Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); + intent.setData(Uri.fromFile(file)); + context.sendBroadcast(intent); + } + } + + public static int getFileWidth(@NonNull String path) { + return getBitmapOptions(path).outWidth; + } + + public static int getFileHeight(@NonNull String path) { + return getBitmapOptions(path).outHeight; + } + + private static BitmapFactory.Options getBitmapOptions(@NonNull String path) { + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + options.inScaled = false; + options.inMutable = true; + Bitmap bitmap = BitmapFactory.decodeFile(path, options); + if (bitmap != null && !bitmap.isRecycled()) { + bitmap.recycle(); + } + return options; + } +} diff --git a/media/src/main/java/com/example/media/utils/GlideUtils.java b/media/src/main/java/com/example/media/utils/GlideUtils.java new file mode 100644 index 0000000..6efee8f --- /dev/null +++ b/media/src/main/java/com/example/media/utils/GlideUtils.java @@ -0,0 +1,40 @@ +package com.example.media.utils; + +import android.content.Context; +import android.support.annotation.DrawableRes; +import android.support.annotation.NonNull; +import android.widget.ImageView; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.GlideBuilder; +import com.bumptech.glide.load.engine.DiskCacheStrategy; +import com.bumptech.glide.load.engine.cache.DiskLruCacheFactory; +import com.bumptech.glide.module.AppGlideModule; +import com.bumptech.glide.request.RequestOptions; +import com.bumptech.glide.request.target.Target; +import com.example.media.R; + +public class GlideUtils { + public static void loadImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView) { + RequestOptions options = new RequestOptions().centerCrop().placeholder(R.mipmap.icon_image_background).error(R.mipmap.icon_image_background) + .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC); + Glide.with(context).asBitmap().apply(options).load(url).into(imageView); + } + + public static void loadImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView, boolean isCenterCrop) { + RequestOptions options = new RequestOptions().placeholder(R.mipmap.icon_image_background) + .error(R.mipmap.icon_image_background).diskCacheStrategy(DiskCacheStrategy.AUTOMATIC); + if (isCenterCrop) { + options = options.centerCrop(); + } else { + options = options.centerInside(); + } + Glide.with(context).asBitmap().apply(options).load(url).into(imageView); + } + + public static void loadImage(@NonNull Context context, @DrawableRes int resId, @NonNull ImageView imageView) { + RequestOptions options = new RequestOptions().centerInside().placeholder(R.mipmap.icon_image_background).error(R.mipmap.icon_image_background).diskCacheStrategy(DiskCacheStrategy.AUTOMATIC); + Glide.with(context).asBitmap().apply(options).load(resId).into(imageView); + } + +} diff --git a/media/src/main/java/com/example/media/utils/ScreenUtils.java b/media/src/main/java/com/example/media/utils/ScreenUtils.java new file mode 100644 index 0000000..7cfb29a --- /dev/null +++ b/media/src/main/java/com/example/media/utils/ScreenUtils.java @@ -0,0 +1,115 @@ +package com.example.media.utils; + +import android.app.Activity; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Color; +import android.graphics.Point; +import android.os.Build; +import android.support.annotation.NonNull; +import android.view.Display; +import android.view.KeyCharacterMap; +import android.view.KeyEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.view.WindowManager; + +public class ScreenUtils { + + + public static int screenWidth(@NonNull Context context) { + return context.getResources().getDisplayMetrics().widthPixels; + } + + public static int screenHeight(@NonNull Context context) { + return context.getResources().getDisplayMetrics().heightPixels; + } + + public static int dp2px(Context context, float dpValue) { + float scale = context.getResources().getDisplayMetrics().density; + return (int) (dpValue * scale + 0.5F); + } + + public static int px2dp(Context context, float pxValue) { + float scale = context.getResources().getDisplayMetrics().density; + return (int) (pxValue / scale + 0.5F); + } + + public static void setDefaultRootViewSize(@NonNull Context context, @NonNull ViewGroup rootView) { + ViewGroup.LayoutParams rootParams = rootView.getLayoutParams(); + rootParams.width = -1; + rootParams.height = dp2px(context, 45.0F); + rootView.setLayoutParams(rootParams); + } + + public static int getStatuWindowsHeight(@NonNull Context context) { + return context.getResources().getDimensionPixelSize(context.getResources().getIdentifier("status_bar_height", "dimen", "android")); + } + /** + * 判断导航栏是否显示 + * + * @param context 上下文 + * @return 导航栏是否显示 + */ + public static boolean isShowDeviceHasNavigationBar(@NonNull Context context) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + if (windowManager == null) { + return false; + } + Display display = windowManager.getDefaultDisplay(); + Point size = new Point(); + Point realSize = new Point(); + display.getSize(size); + display.getRealSize(realSize); + return realSize.y != size.y; + } else { + boolean menu = ViewConfiguration.get(context).hasPermanentMenuKey(); + boolean back = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK); + return !menu && !back; + } + } + + /** + * 隐藏导航栏 + * + * @param activity 显示界面 + */ + public static void hideTransparentNavigation(Activity activity) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + View decorView = activity.getWindow().getDecorView(); + decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_IMMERSIVE + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); + activity.getWindow().setNavigationBarColor(Color.TRANSPARENT); + } + } + + /** + * 显示导航栏 + * + * @param activity 显示界面 + */ + public static void showTransparentNavigation(Activity activity) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + View decorView = activity.getWindow().getDecorView(); + decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); + } + + } + + /** + * 判断导航栏高度 + * + * @param context 上下文 + * @return 导航栏高度 + */ + public static int getNavigationHeight(@NonNull Context context) { + Resources resources = context.getResources(); + int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android"); + return resources.getDimensionPixelSize(resourceId); + } +} diff --git a/media/src/main/java/com/example/media/weight/DialogHelper.java b/media/src/main/java/com/example/media/weight/DialogHelper.java new file mode 100644 index 0000000..5151b0f --- /dev/null +++ b/media/src/main/java/com/example/media/weight/DialogHelper.java @@ -0,0 +1,34 @@ +package com.example.media.weight; + +import android.content.Context; +import android.content.DialogInterface; +import android.support.annotation.NonNull; +import android.support.v7.app.AlertDialog; + +import com.example.media.R; + +/** + * 项 目 : MediaSelector + * 包 名 : com.example.media.weight + * 类 名 : ${CLASS_NAME} + * 作 者 : 胡庆岭 + * 时 间 : 2018/11/10 + * 描 述 : ${TODO} + * + * @author : + */ +public class DialogHelper { + private DialogHelper() { + } + + public static DialogHelper with() { + return new DialogHelper(); + } + + public AlertDialog createDialog(@NonNull Context context, @NonNull String title, @NonNull String message, + @NonNull DialogInterface.OnClickListener onNegativeListener, @NonNull DialogInterface.OnClickListener onPositiveListener) { + return new AlertDialog.Builder(context).setTitle(title).setMessage(message) + .setNegativeButton(R.string.cancel, onNegativeListener).setPositiveButton(R.string.confirm, onPositiveListener) + .create(); + } +} diff --git a/media/src/main/java/com/example/media/weight/FolderWindow.java b/media/src/main/java/com/example/media/weight/FolderWindow.java new file mode 100644 index 0000000..d6befa8 --- /dev/null +++ b/media/src/main/java/com/example/media/weight/FolderWindow.java @@ -0,0 +1,152 @@ +package com.example.media.weight; + +import android.animation.Animator; +import android.animation.ObjectAnimator; +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.drawable.ColorDrawable; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.DefaultItemAnimator; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.LinearInterpolator; +import android.widget.PopupWindow; + +import com.example.item.Contast; +import com.example.media.OnRecyclerItemClickListener; +import com.example.media.R; +import com.example.media.adapter.MediaFolderAdapter; +import com.example.media.bean.MediaSelectorFolder; +import com.example.media.utils.ScreenUtils; + +import java.util.ArrayList; +import java.util.List; + +public class FolderWindow { + private List mFolderData; + private PopupWindow mPopupWindow; + private MediaFolderAdapter mFolderAdapter; + private Context mContext; + private View mViewRoot; + private View mShowView; + + public void setOnPopupItemClickListener(OnPopupItemClickListener onPopupItemClickListener) { + this.onPopupItemClickListener = onPopupItemClickListener; + } + + private OnPopupItemClickListener onPopupItemClickListener; + + public FolderWindow(@NonNull Context context, @Nullable List folderData) { + if (folderData == null) { + folderData = new ArrayList<>(); + } + this.mFolderData = folderData; + this.mContext = context; + createWindows(); + initEvent(); + } + + private void initEvent() { + mViewRoot.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + FolderWindow.this.dismissWindows(); + } + }); + mFolderAdapter.setOnRecyclerItemClickListener(new OnRecyclerItemClickListener() { + @Override + public void itemClick(@NonNull View view, int position) { + if (onPopupItemClickListener != null) { + onPopupItemClickListener.onItemClick(view, position); + } + FolderWindow.this.dismissWindows(); + } + }); + } + + public PopupWindow getFolderWindow() { + return mPopupWindow; + } + + public void dismissWindows() { + windowAnimation(false); + } + + private void createWindows() { + if (mPopupWindow == null) { + mPopupWindow = new PopupWindow(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + mPopupWindow.setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(mContext, R.color.color80000000))); + mPopupWindow.setClippingEnabled(false); + //mPopupWindow.setOutsideTouchable(true); + @SuppressLint("InflateParams") + View inflateView = LayoutInflater.from(mContext).inflate(R.layout.popup_media_view, null, false); + RecyclerView mRvFolder = inflateView.findViewById(R.id.rv_folder); + mViewRoot = inflateView.findViewById(R.id.ll_root); + mRvFolder.setLayoutManager(new LinearLayoutManager(mContext)); + mFolderAdapter = new MediaFolderAdapter(mFolderData); + mRvFolder.setItemAnimator(new DefaultItemAnimator()); + mRvFolder.setAdapter(mFolderAdapter); + mPopupWindow.setContentView(inflateView); + + + // mPopupWindow.setAnimationStyle(R.style.DialogAnimation); + + } + } + + public void showWindows(@NonNull View view) { + this.mShowView = view; + mPopupWindow.showAtLocation(view, Gravity.BOTTOM, 0, ScreenUtils.dp2px(view.getContext(), Contast.DEFAULT_VIEW_HEIGHT)); + windowAnimation(true); + } + + + public interface OnPopupItemClickListener { + void onItemClick(@NonNull View view, int position); + } + + private void windowAnimation(final boolean isOpen) { + ObjectAnimator objectAnimator; + if (isOpen) { + objectAnimator = ObjectAnimator.ofFloat(mViewRoot, "translationY", (ScreenUtils.screenHeight(mContext) - ScreenUtils.dp2px(mContext, mShowView.getHeight())), 0); + } else { + objectAnimator = ObjectAnimator.ofFloat(mViewRoot, "translationY", 0, (ScreenUtils.screenHeight(mContext) - ScreenUtils.dp2px(mContext, mShowView.getHeight()))); + } + objectAnimator.setInterpolator(new LinearInterpolator()); + objectAnimator.setDuration(600); + objectAnimator.start(); + objectAnimator.addListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animation) { + + } + + @Override + public void onAnimationEnd(Animator animation) { + if (!isOpen) { + mPopupWindow.dismiss(); + } + } + + @Override + public void onAnimationCancel(Animator animation) { + if (!isOpen) { + mPopupWindow.dismiss(); + } + } + + @Override + public void onAnimationRepeat(Animator animation) { + + } + }); + + } + +} diff --git a/media/src/main/java/com/example/media/weight/MediaScanner.java b/media/src/main/java/com/example/media/weight/MediaScanner.java new file mode 100644 index 0000000..cfee0b7 --- /dev/null +++ b/media/src/main/java/com/example/media/weight/MediaScanner.java @@ -0,0 +1,49 @@ +package com.example.media.weight; + +import android.content.Context; +import android.media.MediaScannerConnection; +import android.net.Uri; + +import java.io.File; + +/** + * 项 目 : ImageCompress + * 包 名 : com.baixiaohu.imagecompress + * 类 名 : utils.MediaScanner + * 作 者 : 胡庆岭 + * 时 间 : 2018/1/31 0031 上午 11:03 + * 描 述 : ${TODO} + * + * @author : + */ + +public class MediaScanner implements MediaScannerConnection.MediaScannerConnectionClient { + + private MediaScannerConnection mMSC; + private File mImageFile; + + @Override + public void onMediaScannerConnected() { + mMSC.scanFile(mImageFile.getAbsolutePath(), "image"); + } + + @Override + public void onScanCompleted(String s, Uri uri) { + mMSC.disconnect(); + } + + public MediaScanner(Context context, File file) { + this.mImageFile = file; + if (mMSC == null) { + mMSC = new MediaScannerConnection(context, this); + } + + } + + public void refresh() { + if (mMSC != null && !mMSC.isConnected()) { + mMSC.connect(); + } + } + +} diff --git a/media/src/main/java/com/example/media/weight/PreviewViewPager.java b/media/src/main/java/com/example/media/weight/PreviewViewPager.java new file mode 100644 index 0000000..132cd44 --- /dev/null +++ b/media/src/main/java/com/example/media/weight/PreviewViewPager.java @@ -0,0 +1,43 @@ +package com.example.media.weight; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.view.ViewPager; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.ViewGroup; + +import com.example.media.utils.ScreenUtils; + +public class PreviewViewPager extends ViewPager { + public PreviewViewPager(@NonNull Context context) { + super(context); + } + + public PreviewViewPager(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + try { + return super.dispatchTouchEvent(ev); + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + try { + return super.onTouchEvent(ev); + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } +} diff --git a/media/src/main/java/com/example/media/weight/Toasts.java b/media/src/main/java/com/example/media/weight/Toasts.java new file mode 100644 index 0000000..3160890 --- /dev/null +++ b/media/src/main/java/com/example/media/weight/Toasts.java @@ -0,0 +1,54 @@ +package com.example.media.weight; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.os.Looper; +import android.support.annotation.NonNull; +import android.support.annotation.StringRes; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.TextView; +import android.widget.Toast; + +import com.example.media.R; + +public class Toasts { + + + private Toasts() { + + } + + private static Toasts mToasts = new Toasts(); + + public static Toasts with() { + return mToasts; + } + + private Toast mToast; + + public void showToast(@NonNull Context context, @NonNull String text) { + if (mToast == null) { + mToast = Toast.makeText(context.getApplicationContext(),text, Toast.LENGTH_SHORT); + + } else { + mToast.setText(text); + mToast.setDuration(Toast.LENGTH_SHORT); + } + Log.w("showToast--", "showToast"); + mToast.show(); + } + + public synchronized void showToast(@NonNull Context context, @StringRes int text, Object... object) { + + if (mToast == null) { + mToast = Toast.makeText(context.getApplicationContext(), context.getString(text, object), Toast.LENGTH_SHORT); + } else { + mToast.setText(context.getString(text, object)); + mToast.setDuration(Toast.LENGTH_SHORT); + } + Log.w("showToast--", "showToast"); + mToast.show(); + } +} diff --git a/media/src/main/res/anim/anim_dialog_in.xml b/media/src/main/res/anim/anim_dialog_in.xml new file mode 100644 index 0000000..aba5cc0 --- /dev/null +++ b/media/src/main/res/anim/anim_dialog_in.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/media/src/main/res/anim/anim_dialog_out.xml b/media/src/main/res/anim/anim_dialog_out.xml new file mode 100644 index 0000000..54856c7 --- /dev/null +++ b/media/src/main/res/anim/anim_dialog_out.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/media/src/main/res/drawable/selector_item_image.xml b/media/src/main/res/drawable/selector_item_image.xml new file mode 100644 index 0000000..b2a1a15 --- /dev/null +++ b/media/src/main/res/drawable/selector_item_image.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/media/src/main/res/drawable/selector_item_video_status.xml b/media/src/main/res/drawable/selector_item_video_status.xml new file mode 100644 index 0000000..21fa60d --- /dev/null +++ b/media/src/main/res/drawable/selector_item_video_status.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/media/src/main/res/drawable/shape_media_check.xml b/media/src/main/res/drawable/shape_media_check.xml new file mode 100644 index 0000000..f83ed15 --- /dev/null +++ b/media/src/main/res/drawable/shape_media_check.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/media/src/main/res/drawable/shape_media_uncheck.xml b/media/src/main/res/drawable/shape_media_uncheck.xml new file mode 100644 index 0000000..9e752a8 --- /dev/null +++ b/media/src/main/res/drawable/shape_media_uncheck.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/media/src/main/res/layout/activity_media.xml b/media/src/main/res/layout/activity_media.xml new file mode 100644 index 0000000..b278baf --- /dev/null +++ b/media/src/main/res/layout/activity_media.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/media/src/main/res/layout/activity_preview.xml b/media/src/main/res/layout/activity_preview.xml new file mode 100644 index 0000000..75e18b2 --- /dev/null +++ b/media/src/main/res/layout/activity_preview.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + diff --git a/media/src/main/res/layout/item_camera_media_view.xml b/media/src/main/res/layout/item_camera_media_view.xml new file mode 100644 index 0000000..aef1fd2 --- /dev/null +++ b/media/src/main/res/layout/item_camera_media_view.xml @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/media/src/main/res/layout/item_check_media_view.xml b/media/src/main/res/layout/item_check_media_view.xml new file mode 100644 index 0000000..1a86734 --- /dev/null +++ b/media/src/main/res/layout/item_check_media_view.xml @@ -0,0 +1,22 @@ + + + + + + \ No newline at end of file diff --git a/media/src/main/res/layout/item_media_file_view.xml b/media/src/main/res/layout/item_media_file_view.xml new file mode 100644 index 0000000..bf1036c --- /dev/null +++ b/media/src/main/res/layout/item_media_file_view.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/media/src/main/res/layout/item_media_folder.xml b/media/src/main/res/layout/item_media_folder.xml new file mode 100644 index 0000000..902d512 --- /dev/null +++ b/media/src/main/res/layout/item_media_folder.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/media/src/main/res/layout/item_video_play_view.xml b/media/src/main/res/layout/item_video_play_view.xml new file mode 100644 index 0000000..f0facbd --- /dev/null +++ b/media/src/main/res/layout/item_video_play_view.xml @@ -0,0 +1,21 @@ + + + + + + + + + \ No newline at end of file diff --git a/media/src/main/res/layout/popup_media_view.xml b/media/src/main/res/layout/popup_media_view.xml new file mode 100644 index 0000000..8257933 --- /dev/null +++ b/media/src/main/res/layout/popup_media_view.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/media/src/main/res/mipmap-xhdpi/icon_image_background.png b/media/src/main/res/mipmap-xhdpi/icon_image_background.png new file mode 100644 index 0000000..5c4f263 Binary files /dev/null and b/media/src/main/res/mipmap-xhdpi/icon_image_background.png differ diff --git a/media/src/main/res/mipmap-xhdpi/icon_image_type.png b/media/src/main/res/mipmap-xhdpi/icon_image_type.png new file mode 100644 index 0000000..7e36af4 Binary files /dev/null and b/media/src/main/res/mipmap-xhdpi/icon_image_type.png differ diff --git a/media/src/main/res/mipmap-xhdpi/icon_video_pause.png b/media/src/main/res/mipmap-xhdpi/icon_video_pause.png new file mode 100644 index 0000000..da1c107 Binary files /dev/null and b/media/src/main/res/mipmap-xhdpi/icon_video_pause.png differ diff --git a/media/src/main/res/mipmap-xhdpi/icon_video_start.png b/media/src/main/res/mipmap-xhdpi/icon_video_start.png new file mode 100644 index 0000000..2270241 Binary files /dev/null and b/media/src/main/res/mipmap-xhdpi/icon_video_start.png differ diff --git a/media/src/main/res/mipmap-xxhdpi/icon_camera.png b/media/src/main/res/mipmap-xxhdpi/icon_camera.png new file mode 100644 index 0000000..b4f3c26 Binary files /dev/null and b/media/src/main/res/mipmap-xxhdpi/icon_camera.png differ diff --git a/media/src/main/res/mipmap-xxhdpi/icon_folder_check.png b/media/src/main/res/mipmap-xxhdpi/icon_folder_check.png new file mode 100644 index 0000000..63e2be8 Binary files /dev/null and b/media/src/main/res/mipmap-xxhdpi/icon_folder_check.png differ diff --git a/media/src/main/res/mipmap-xxhdpi/icon_folder_uncheck.png b/media/src/main/res/mipmap-xxhdpi/icon_folder_uncheck.png new file mode 100644 index 0000000..560688a Binary files /dev/null and b/media/src/main/res/mipmap-xxhdpi/icon_folder_uncheck.png differ diff --git a/media/src/main/res/mipmap-xxhdpi/icon_image_back.png b/media/src/main/res/mipmap-xxhdpi/icon_image_back.png new file mode 100644 index 0000000..917a131 Binary files /dev/null and b/media/src/main/res/mipmap-xxhdpi/icon_image_back.png differ diff --git a/media/src/main/res/mipmap-xxhdpi/icon_image_checked.png b/media/src/main/res/mipmap-xxhdpi/icon_image_checked.png new file mode 100644 index 0000000..c3e13ff Binary files /dev/null and b/media/src/main/res/mipmap-xxhdpi/icon_image_checked.png differ diff --git a/media/src/main/res/mipmap-xxhdpi/icon_image_unchecked.png b/media/src/main/res/mipmap-xxhdpi/icon_image_unchecked.png new file mode 100644 index 0000000..68df95d Binary files /dev/null and b/media/src/main/res/mipmap-xxhdpi/icon_image_unchecked.png differ diff --git a/media/src/main/res/mipmap-xxhdpi/icon_preview_check.png b/media/src/main/res/mipmap-xxhdpi/icon_preview_check.png new file mode 100644 index 0000000..2f04437 Binary files /dev/null and b/media/src/main/res/mipmap-xxhdpi/icon_preview_check.png differ diff --git a/media/src/main/res/mipmap-xxhdpi/icon_preview_uncheck.png b/media/src/main/res/mipmap-xxhdpi/icon_preview_uncheck.png new file mode 100644 index 0000000..42a2fd3 Binary files /dev/null and b/media/src/main/res/mipmap-xxhdpi/icon_preview_uncheck.png differ diff --git a/media/src/main/res/mipmap-xxhdpi/icon_type_video.png b/media/src/main/res/mipmap-xxhdpi/icon_type_video.png new file mode 100644 index 0000000..488b7f9 Binary files /dev/null and b/media/src/main/res/mipmap-xxhdpi/icon_type_video.png differ diff --git a/media/src/main/res/values/colors.xml b/media/src/main/res/values/colors.xml new file mode 100644 index 0000000..c1fd1a1 --- /dev/null +++ b/media/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FF303030 + #FFEEEEEE + #FF285428 + #FF1F8F1F + #FF191814 + #80000000 + #A0000000 + diff --git a/media/src/main/res/values/strings.xml b/media/src/main/res/values/strings.xml new file mode 100644 index 0000000..3d931ab --- /dev/null +++ b/media/src/main/res/values/strings.xml @@ -0,0 +1,25 @@ + + media + 返回 + 完成 + 全部图片 + 预览 + %s张 + %s/%s + 选择 + 完成(%s/%s) + 最大选择%s张 + 提示 + 取消 + 确定 + 相机 + %s为必要权限,请允许,否则无法使用 + 储存卡 + 没有获取到照片 + 压缩图片失败 + 该视频格式不支持 + 裁剪图片失败 + 视频不支持裁剪 + 文件不存在 + + diff --git a/media/src/main/res/values/styles.xml b/media/src/main/res/values/styles.xml new file mode 100644 index 0000000..d055f4e --- /dev/null +++ b/media/src/main/res/values/styles.xml @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/media/src/main/res/xml/provider_path.xml b/media/src/main/res/xml/provider_path.xml new file mode 100644 index 0000000..78fe384 --- /dev/null +++ b/media/src/main/res/xml/provider_path.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 9230338..a7c22c0 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':app', ':compress',':matisse' +include ':app', ':compress',':media'