From 4973236469218701781dfaefb0e5f537257312fb Mon Sep 17 00:00:00 2001 From: lvmeng <848755140@qq.com> Date: Sat, 27 Sep 2025 23:26:18 +0800 Subject: [PATCH] =?UTF-8?q?matisse=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- coalMiningApp/matisse/build.gradle | 84 ++++ coalMiningApp/matisse/gradle.properties | 0 coalMiningApp/matisse/proguard-rules.pro | 19 + .../matisse/src/main/AndroidManifest.xml | 29 ++ .../main/java/com/zhihu/matisse/Matisse.java | 151 ++++++ .../main/java/com/zhihu/matisse/MimeType.java | 178 +++++++ .../com/zhihu/matisse/SelectionCreator.java | 371 +++++++++++++++ .../com/zhihu/matisse/engine/ImageEngine.java | 82 ++++ .../matisse/engine/impl/GlideEngine.java | 87 ++++ .../matisse/engine/impl/PicassoEngine.java | 61 +++ .../java/com/zhihu/matisse/filter/Filter.java | 69 +++ .../zhihu/matisse/internal/entity/Album.java | 122 +++++ .../internal/entity/CaptureStrategy.java | 33 ++ .../internal/entity/IncapableCause.java | 83 ++++ .../zhihu/matisse/internal/entity/Item.java | 144 ++++++ .../internal/entity/SelectionSpec.java | 121 +++++ .../matisse/internal/loader/AlbumLoader.java | 293 ++++++++++++ .../internal/loader/AlbumMediaLoader.java | 197 ++++++++ .../internal/model/AlbumCollection.java | 114 +++++ .../internal/model/AlbumMediaCollection.java | 107 +++++ .../model/SelectedItemCollection.java | 256 ++++++++++ .../internal/ui/AlbumPreviewActivity.java | 97 ++++ .../internal/ui/BasePreviewActivity.java | 358 ++++++++++++++ .../internal/ui/MediaSelectionFragment.java | 159 +++++++ .../internal/ui/PreviewItemFragment.java | 129 ++++++ .../internal/ui/SelectedPreviewActivity.java | 51 ++ .../ui/adapter/AlbumMediaAdapter.java | 300 ++++++++++++ .../internal/ui/adapter/AlbumsAdapter.java | 71 +++ .../ui/adapter/PreviewPagerAdapter.java | 70 +++ .../ui/adapter/RecyclerViewCursorAdapter.java | 105 +++++ .../internal/ui/widget/AlbumsSpinner.java | 129 ++++++ .../internal/ui/widget/CheckRadioView.java | 60 +++ .../matisse/internal/ui/widget/CheckView.java | 229 +++++++++ .../internal/ui/widget/IncapableDialog.java | 64 +++ .../matisse/internal/ui/widget/MediaGrid.java | 161 +++++++ .../internal/ui/widget/MediaGridInset.java | 60 +++ .../internal/ui/widget/PreviewViewPager.java | 38 ++ .../ui/widget/RoundedRectangleImageView.java | 65 +++ .../internal/ui/widget/SquareFrameLayout.java | 36 ++ .../internal/utils/ExifInterfaceCompat.java | 131 ++++++ .../internal/utils/MediaStoreCompat.java | 145 ++++++ .../matisse/internal/utils/PathUtils.java | 135 ++++++ .../internal/utils/PhotoMetadataUtils.java | 178 +++++++ .../matisse/internal/utils/Platform.java | 16 + .../internal/utils/SingleMediaScanner.java | 44 ++ .../zhihu/matisse/internal/utils/UIUtils.java | 32 ++ .../matisse/listener/OnCheckedListener.java | 9 + .../OnFragmentInteractionListener.java | 11 + .../matisse/listener/OnSelectedListener.java | 30 ++ .../com/zhihu/matisse/ui/MatisseActivity.java | 437 ++++++++++++++++++ .../color/dracula_bottom_toolbar_apply.xml | 21 + .../color/dracula_bottom_toolbar_preview.xml | 21 + .../dracula_preview_bottom_toolbar_apply.xml | 21 + .../res/color/zhihu_bottom_toolbar_apply.xml | 21 + .../color/zhihu_bottom_toolbar_preview.xml | 21 + .../zhihu_preview_bottom_toolbar_apply.xml | 21 + .../ic_arrow_drop_down_white_24dp.png | Bin 0 -> 123 bytes .../res/drawable-hdpi/ic_check_white_18dp.png | Bin 0 -> 152 bytes .../res/drawable-hdpi/ic_empty_dracula.png | Bin 0 -> 5911 bytes .../main/res/drawable-hdpi/ic_empty_zhihu.png | Bin 0 -> 5785 bytes .../src/main/res/drawable-hdpi/ic_gif.png | Bin 0 -> 929 bytes .../ic_play_circle_outline_white_48dp.png | Bin 0 -> 1023 bytes .../drawable-hdpi/ic_preview_radio_off.webp | Bin 0 -> 290 bytes .../drawable-hdpi/ic_preview_radio_on.webp | Bin 0 -> 338 bytes .../ic_arrow_drop_down_white_24dp.png | Bin 0 -> 95 bytes .../res/drawable-mdpi/ic_check_white_18dp.png | Bin 0 -> 146 bytes .../res/drawable-mdpi/ic_empty_dracula.png | Bin 0 -> 4018 bytes .../main/res/drawable-mdpi/ic_empty_zhihu.png | Bin 0 -> 3843 bytes .../src/main/res/drawable-mdpi/ic_gif.png | Bin 0 -> 638 bytes .../ic_play_circle_outline_white_48dp.png | Bin 0 -> 699 bytes .../drawable-mdpi/ic_preview_radio_off.webp | Bin 0 -> 410 bytes .../drawable-mdpi/ic_preview_radio_on.webp | Bin 0 -> 486 bytes .../ic_arrow_drop_down_white_24dp.png | Bin 0 -> 120 bytes .../drawable-xhdpi/ic_check_white_18dp.png | Bin 0 -> 181 bytes .../res/drawable-xhdpi/ic_empty_dracula.png | Bin 0 -> 8159 bytes .../res/drawable-xhdpi/ic_empty_zhihu.png | Bin 0 -> 7977 bytes .../src/main/res/drawable-xhdpi/ic_gif.png | Bin 0 -> 993 bytes .../ic_play_circle_outline_white_48dp.png | Bin 0 -> 1379 bytes .../drawable-xhdpi/ic_preview_radio_off.webp | Bin 0 -> 544 bytes .../drawable-xhdpi/ic_preview_radio_on.webp | Bin 0 -> 644 bytes .../ic_arrow_drop_down_white_24dp.png | Bin 0 -> 152 bytes .../drawable-xxhdpi/ic_check_white_18dp.png | Bin 0 -> 236 bytes .../res/drawable-xxhdpi/ic_empty_dracula.png | Bin 0 -> 13087 bytes .../res/drawable-xxhdpi/ic_empty_zhihu.png | Bin 0 -> 12785 bytes .../src/main/res/drawable-xxhdpi/ic_gif.png | Bin 0 -> 1380 bytes .../ic_play_circle_outline_white_48dp.png | Bin 0 -> 2145 bytes .../ic_arrow_drop_down_white_24dp.png | Bin 0 -> 185 bytes .../drawable-xxxhdpi/ic_check_white_18dp.png | Bin 0 -> 276 bytes .../res/drawable-xxxhdpi/ic_empty_dracula.png | Bin 0 -> 17923 bytes .../res/drawable-xxxhdpi/ic_empty_zhihu.png | Bin 0 -> 17553 bytes .../src/main/res/drawable-xxxhdpi/ic_gif.png | Bin 0 -> 1712 bytes .../ic_photo_camera_white_24dp.png | Bin 0 -> 894 bytes .../ic_play_circle_outline_white_48dp.png | Bin 0 -> 2836 bytes .../src/main/res/layout/activity_matisse.xml | 137 ++++++ .../res/layout/activity_media_preview.xml | 130 ++++++ .../src/main/res/layout/album_list_item.xml | 57 +++ .../res/layout/fragment_media_selection.xml | 31 ++ .../main/res/layout/fragment_preview_item.xml | 32 ++ .../main/res/layout/media_grid_content.xml | 50 ++ .../src/main/res/layout/media_grid_item.xml | 21 + .../main/res/layout/photo_capture_item.xml | 36 ++ .../src/main/res/values-ar/strings.xml | 20 + .../src/main/res/values-ca/strings.xml | 35 ++ .../src/main/res/values-de/strings.xml | 32 ++ .../src/main/res/values-es/strings.xml | 35 ++ .../src/main/res/values-it/strings.xml | 35 ++ .../src/main/res/values-ko/strings.xml | 18 + .../src/main/res/values-pl/strings.xml | 38 ++ .../src/main/res/values-pt-rBR/strings.xml | 35 ++ .../src/main/res/values-ru/strings.xml | 43 ++ .../src/main/res/values-tr-rTR/strings.xml | 35 ++ .../src/main/res/values-uk/strings.xml | 40 ++ .../src/main/res/values-vi/strings.xml | 23 + .../src/main/res/values-zh-rTW/strings.xml | 38 ++ .../src/main/res/values-zh/strings.xml | 47 ++ .../matisse/src/main/res/values/attrs.xml | 36 ++ .../matisse/src/main/res/values/colors.xml | 22 + .../src/main/res/values/colors_dracula.xml | 43 ++ .../src/main/res/values/colors_zhihu.xml | 45 ++ .../matisse/src/main/res/values/dimens.xml | 22 + .../matisse/src/main/res/values/strings.xml | 49 ++ .../matisse/src/main/res/values/styles.xml | 86 ++++ 122 files changed, 7348 insertions(+) create mode 100644 coalMiningApp/matisse/build.gradle create mode 100644 coalMiningApp/matisse/gradle.properties create mode 100644 coalMiningApp/matisse/proguard-rules.pro create mode 100644 coalMiningApp/matisse/src/main/AndroidManifest.xml create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/Matisse.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/MimeType.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/SelectionCreator.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/engine/ImageEngine.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/engine/impl/GlideEngine.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/engine/impl/PicassoEngine.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/filter/Filter.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/entity/Album.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/entity/CaptureStrategy.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/entity/IncapableCause.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/entity/Item.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/entity/SelectionSpec.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/loader/AlbumLoader.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/loader/AlbumMediaLoader.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/model/AlbumCollection.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/model/AlbumMediaCollection.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/model/SelectedItemCollection.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/AlbumPreviewActivity.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/BasePreviewActivity.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/MediaSelectionFragment.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/PreviewItemFragment.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/SelectedPreviewActivity.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/AlbumMediaAdapter.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/AlbumsAdapter.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/PreviewPagerAdapter.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/RecyclerViewCursorAdapter.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/AlbumsSpinner.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/CheckRadioView.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/CheckView.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/IncapableDialog.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/MediaGrid.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/MediaGridInset.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/PreviewViewPager.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/RoundedRectangleImageView.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/SquareFrameLayout.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/utils/ExifInterfaceCompat.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/utils/MediaStoreCompat.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/utils/PathUtils.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/utils/PhotoMetadataUtils.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/utils/Platform.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/utils/SingleMediaScanner.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/utils/UIUtils.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/listener/OnCheckedListener.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/listener/OnFragmentInteractionListener.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/listener/OnSelectedListener.java create mode 100644 coalMiningApp/matisse/src/main/java/com/zhihu/matisse/ui/MatisseActivity.java create mode 100644 coalMiningApp/matisse/src/main/res/color/dracula_bottom_toolbar_apply.xml create mode 100644 coalMiningApp/matisse/src/main/res/color/dracula_bottom_toolbar_preview.xml create mode 100644 coalMiningApp/matisse/src/main/res/color/dracula_preview_bottom_toolbar_apply.xml create mode 100644 coalMiningApp/matisse/src/main/res/color/zhihu_bottom_toolbar_apply.xml create mode 100644 coalMiningApp/matisse/src/main/res/color/zhihu_bottom_toolbar_preview.xml create mode 100644 coalMiningApp/matisse/src/main/res/color/zhihu_preview_bottom_toolbar_apply.xml create mode 100644 coalMiningApp/matisse/src/main/res/drawable-hdpi/ic_arrow_drop_down_white_24dp.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-hdpi/ic_check_white_18dp.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-hdpi/ic_empty_dracula.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-hdpi/ic_empty_zhihu.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-hdpi/ic_gif.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-hdpi/ic_play_circle_outline_white_48dp.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-hdpi/ic_preview_radio_off.webp create mode 100644 coalMiningApp/matisse/src/main/res/drawable-hdpi/ic_preview_radio_on.webp create mode 100644 coalMiningApp/matisse/src/main/res/drawable-mdpi/ic_arrow_drop_down_white_24dp.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-mdpi/ic_check_white_18dp.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-mdpi/ic_empty_dracula.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-mdpi/ic_empty_zhihu.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-mdpi/ic_gif.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-mdpi/ic_play_circle_outline_white_48dp.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-mdpi/ic_preview_radio_off.webp create mode 100644 coalMiningApp/matisse/src/main/res/drawable-mdpi/ic_preview_radio_on.webp create mode 100644 coalMiningApp/matisse/src/main/res/drawable-xhdpi/ic_arrow_drop_down_white_24dp.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-xhdpi/ic_check_white_18dp.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-xhdpi/ic_empty_dracula.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-xhdpi/ic_empty_zhihu.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-xhdpi/ic_gif.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-xhdpi/ic_play_circle_outline_white_48dp.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-xhdpi/ic_preview_radio_off.webp create mode 100644 coalMiningApp/matisse/src/main/res/drawable-xhdpi/ic_preview_radio_on.webp create mode 100644 coalMiningApp/matisse/src/main/res/drawable-xxhdpi/ic_arrow_drop_down_white_24dp.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-xxhdpi/ic_check_white_18dp.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-xxhdpi/ic_empty_dracula.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-xxhdpi/ic_empty_zhihu.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-xxhdpi/ic_gif.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-xxhdpi/ic_play_circle_outline_white_48dp.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-xxxhdpi/ic_arrow_drop_down_white_24dp.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-xxxhdpi/ic_check_white_18dp.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-xxxhdpi/ic_empty_dracula.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-xxxhdpi/ic_empty_zhihu.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-xxxhdpi/ic_gif.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-xxxhdpi/ic_photo_camera_white_24dp.png create mode 100644 coalMiningApp/matisse/src/main/res/drawable-xxxhdpi/ic_play_circle_outline_white_48dp.png create mode 100644 coalMiningApp/matisse/src/main/res/layout/activity_matisse.xml create mode 100644 coalMiningApp/matisse/src/main/res/layout/activity_media_preview.xml create mode 100644 coalMiningApp/matisse/src/main/res/layout/album_list_item.xml create mode 100644 coalMiningApp/matisse/src/main/res/layout/fragment_media_selection.xml create mode 100644 coalMiningApp/matisse/src/main/res/layout/fragment_preview_item.xml create mode 100644 coalMiningApp/matisse/src/main/res/layout/media_grid_content.xml create mode 100644 coalMiningApp/matisse/src/main/res/layout/media_grid_item.xml create mode 100644 coalMiningApp/matisse/src/main/res/layout/photo_capture_item.xml create mode 100644 coalMiningApp/matisse/src/main/res/values-ar/strings.xml create mode 100644 coalMiningApp/matisse/src/main/res/values-ca/strings.xml create mode 100644 coalMiningApp/matisse/src/main/res/values-de/strings.xml create mode 100644 coalMiningApp/matisse/src/main/res/values-es/strings.xml create mode 100644 coalMiningApp/matisse/src/main/res/values-it/strings.xml create mode 100644 coalMiningApp/matisse/src/main/res/values-ko/strings.xml create mode 100644 coalMiningApp/matisse/src/main/res/values-pl/strings.xml create mode 100644 coalMiningApp/matisse/src/main/res/values-pt-rBR/strings.xml create mode 100644 coalMiningApp/matisse/src/main/res/values-ru/strings.xml create mode 100644 coalMiningApp/matisse/src/main/res/values-tr-rTR/strings.xml create mode 100644 coalMiningApp/matisse/src/main/res/values-uk/strings.xml create mode 100644 coalMiningApp/matisse/src/main/res/values-vi/strings.xml create mode 100644 coalMiningApp/matisse/src/main/res/values-zh-rTW/strings.xml create mode 100644 coalMiningApp/matisse/src/main/res/values-zh/strings.xml create mode 100644 coalMiningApp/matisse/src/main/res/values/attrs.xml create mode 100644 coalMiningApp/matisse/src/main/res/values/colors.xml create mode 100644 coalMiningApp/matisse/src/main/res/values/colors_dracula.xml create mode 100644 coalMiningApp/matisse/src/main/res/values/colors_zhihu.xml create mode 100644 coalMiningApp/matisse/src/main/res/values/dimens.xml create mode 100644 coalMiningApp/matisse/src/main/res/values/strings.xml create mode 100644 coalMiningApp/matisse/src/main/res/values/styles.xml diff --git a/coalMiningApp/matisse/build.gradle b/coalMiningApp/matisse/build.gradle new file mode 100644 index 0000000..050d9a7 --- /dev/null +++ b/coalMiningApp/matisse/build.gradle @@ -0,0 +1,84 @@ +/* + * 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: 'com.novoda.bintray-release'/ +//apply plugin: 'checkstyle' + +android { +// compileSdkVersion 29 +// buildToolsVersion '29.0.2' + compileSdk rootProject.ext.compileSdkVersion + + defaultConfig { +// minSdkVersion 14 +// targetSdkVersion 29 + minSdk rootProject.ext.minSdkVersion + targetSdk rootProject.ext.targetSdkVersion + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + lintOptions { + abortOnError false + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + + implementation "androidx.appcompat:appcompat:1.1.0" + implementation "androidx.annotation:annotation:1.1.0" + implementation "androidx.recyclerview:recyclerview:1.0.0" + implementation 'it.sephiroth.android.library.imagezoom:library:1.0.4' + + compileOnly 'com.github.bumptech.glide:glide:4.9.0' + compileOnly 'com.squareup.picasso:picasso:2.5.2' +} + +// jcenter configuration for novoda's bintray-release +// $ ./gradlew clean build bintrayUpload -PbintrayUser=BINTRAY_USERNAME -PbintrayKey=BINTRAY_KEY -PdryRun=false +//publish { +// userOrg = 'zhihu' +// groupId = 'com.zhihu.android' +// artifactId = 'matisse' +// publishVersion = '0.5.3-beta3' +// desc = 'A well-designed local image selector for Android' +// website = 'https://www.zhihu.com/' +//} + +//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/coalMiningApp/matisse/gradle.properties b/coalMiningApp/matisse/gradle.properties new file mode 100644 index 0000000..e69de29 diff --git a/coalMiningApp/matisse/proguard-rules.pro b/coalMiningApp/matisse/proguard-rules.pro new file mode 100644 index 0000000..f1ffffd --- /dev/null +++ b/coalMiningApp/matisse/proguard-rules.pro @@ -0,0 +1,19 @@ +# 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/coalMiningApp/matisse/src/main/AndroidManifest.xml b/coalMiningApp/matisse/src/main/AndroidManifest.xml new file mode 100644 index 0000000..7057835 --- /dev/null +++ b/coalMiningApp/matisse/src/main/AndroidManifest.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/Matisse.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/Matisse.java new file mode 100644 index 0000000..0de5938 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/Matisse.java @@ -0,0 +1,151 @@ +/* + * 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 androidx.annotation.Nullable; +import androidx.fragment.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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/MimeType.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/MimeType.java new file mode 100644 index 0000000..edbcced --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/MimeType.java @@ -0,0 +1,178 @@ +/* + * 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 androidx.collection.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 ofImage(boolean onlyGif) { + return EnumSet.of(GIF); + } + + public static Set ofGif() { + return ofImage(true); + } + + public static Set ofVideo() { + return EnumSet.of(MPEG, MP4, QUICKTIME, THREEGPP, THREEGPP2, MKV, WEBM, TS, AVI); + } + + public static boolean isImage(String mimeType) { + if (mimeType == null) return false; + return mimeType.startsWith("image"); + } + + public static boolean isVideo(String mimeType) { + if (mimeType == null) return false; + return mimeType.startsWith("video"); + } + + public static boolean isGif(String mimeType) { + if (mimeType == null) return false; + return mimeType.equals(MimeType.GIF.toString()); + } + + 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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/SelectionCreator.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/SelectionCreator.java new file mode 100644 index 0000000..66aeadf --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/SelectionCreator.java @@ -0,0 +1,371 @@ +/* + * 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 androidx.annotation.IntDef; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; +import androidx.annotation.StyleRes; +import androidx.fragment.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 androidx.core.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); + } + } + + public SelectionCreator showPreview(boolean showPreview) { + mSelectionSpec.showPreview = showPreview; + return this; + } +} diff --git a/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/engine/ImageEngine.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/engine/ImageEngine.java new file mode 100644 index 0000000..84e5c96 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/engine/ImageEngine.java @@ -0,0 +1,82 @@ +/* + * 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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/engine/impl/GlideEngine.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/engine/impl/GlideEngine.java new file mode 100644 index 0000000..51157ae --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/engine/impl/GlideEngine.java @@ -0,0 +1,87 @@ +/* + * 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) + .asBitmap() // some .jpeg files are actually gif + .load(uri) + .apply(new RequestOptions() + .override(resize, resize) + .placeholder(placeholder) + .centerCrop()) + .into(imageView); + } + + @Override + public void loadGifThumbnail(Context context, int resize, Drawable placeholder, ImageView imageView, + Uri uri) { + Glide.with(context) + .asBitmap() // some .jpeg files are actually gif + .load(uri) + .apply(new RequestOptions() + .override(resize, resize) + .placeholder(placeholder) + .centerCrop()) + .into(imageView); + } + + @Override + public void loadImage(Context context, int resizeX, int resizeY, ImageView imageView, Uri uri) { + Glide.with(context) + .load(uri) + .apply(new RequestOptions() + .override(resizeX, resizeY) + .priority(Priority.HIGH) + .fitCenter()) + .into(imageView); + } + + @Override + public void loadGifImage(Context context, int resizeX, int resizeY, ImageView imageView, Uri uri) { + Glide.with(context) + .asGif() + .load(uri) + .apply(new RequestOptions() + .override(resizeX, resizeY) + .priority(Priority.HIGH) + .fitCenter()) + .into(imageView); + } + + @Override + public boolean supportAnimatedGif() { + return true; + } + +} diff --git a/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/engine/impl/PicassoEngine.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/engine/impl/PicassoEngine.java new file mode 100644 index 0000000..4ee33ea --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/engine/impl/PicassoEngine.java @@ -0,0 +1,61 @@ +/* + * 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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/filter/Filter.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/filter/Filter.java new file mode 100644 index 0000000..0942364 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/filter/Filter.java @@ -0,0 +1,69 @@ +/* + * 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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/entity/Album.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/entity/Album.java new file mode 100644 index 0000000..35490e9 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/entity/Album.java @@ -0,0 +1,122 @@ +/* + * 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.net.Uri; +import android.os.Parcel; +import android.os.Parcelable; + +import androidx.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 Uri mCoverUri; + private final String mDisplayName; + private long mCount; + + public Album(String id, Uri coverUri, String albumName, long count) { + mId = id; + mCoverUri = coverUri; + mDisplayName = albumName; + mCount = count; + } + + private Album(Parcel source) { + mId = source.readString(); + mCoverUri = source.readParcelable(Uri.class.getClassLoader()); + 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) { + String clumn = cursor.getString(cursor.getColumnIndex(AlbumLoader.COLUMN_URI)); + return new Album( + cursor.getString(cursor.getColumnIndex("bucket_id")), + Uri.parse(clumn != null ? clumn : ""), + 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.writeParcelable(mCoverUri, 0); + dest.writeString(mDisplayName); + dest.writeLong(mCount); + } + + public String getId() { + return mId; + } + + public Uri getCoverUri() { + return mCoverUri; + } + + 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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/entity/CaptureStrategy.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/entity/CaptureStrategy.java new file mode 100644 index 0000000..c4de7ca --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/entity/CaptureStrategy.java @@ -0,0 +1,33 @@ +/* + * 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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/entity/IncapableCause.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/entity/IncapableCause.java new file mode 100644 index 0000000..ff5ec46 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/entity/IncapableCause.java @@ -0,0 +1,83 @@ +/* + * 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 androidx.annotation.IntDef; +import androidx.fragment.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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/entity/Item.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/entity/Item.java new file mode 100644 index 0000000..eda9bb5 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/entity/Item.java @@ -0,0 +1,144 @@ +/* + * 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 androidx.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() { + return MimeType.isImage(mimeType); + } + + public boolean isGif() { + return MimeType.isGif(mimeType); + } + + public boolean isVideo() { + return MimeType.isVideo(mimeType); + } + + @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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/entity/SelectionSpec.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/entity/SelectionSpec.java new file mode 100644 index 0000000..80b7d10 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/entity/SelectionSpec.java @@ -0,0 +1,121 @@ +/* + * 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 androidx.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; + public boolean showPreview; + + 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; + showPreview = true; + } + + 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); + } + + public boolean onlyShowGif() { + return showSingleMediaType && MimeType.ofGif().equals(mimeTypeSet); + } + + private static final class InstanceHolder { + private static final SelectionSpec INSTANCE = new SelectionSpec(); + } +} diff --git a/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/loader/AlbumLoader.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/loader/AlbumLoader.java new file mode 100644 index 0000000..157a563 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/loader/AlbumLoader.java @@ -0,0 +1,293 @@ +/* + * 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.ContentUris; +import android.content.Context; +import android.database.Cursor; +import android.database.MatrixCursor; +import android.database.MergeCursor; +import android.net.Uri; +import android.os.Build; +import android.provider.MediaStore; + +import androidx.loader.content.CursorLoader; + +import com.zhihu.matisse.MimeType; +import com.zhihu.matisse.internal.entity.Album; +import com.zhihu.matisse.internal.entity.SelectionSpec; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * Load all albums (grouped by bucket_id) into a single cursor. + */ +public class AlbumLoader extends CursorLoader { + + private static final String COLUMN_BUCKET_ID = "bucket_id"; + private static final String COLUMN_BUCKET_DISPLAY_NAME = "bucket_display_name"; + public static final String COLUMN_URI = "uri"; + 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, + COLUMN_BUCKET_ID, + COLUMN_BUCKET_DISPLAY_NAME, + MediaStore.MediaColumns.MIME_TYPE, + COLUMN_URI, + COLUMN_COUNT}; + + private static final String[] PROJECTION = { + MediaStore.Files.FileColumns._ID, + COLUMN_BUCKET_ID, + COLUMN_BUCKET_DISPLAY_NAME, + MediaStore.MediaColumns.MIME_TYPE, + "COUNT(*) AS " + COLUMN_COUNT}; + + private static final String[] PROJECTION_29 = { + MediaStore.Files.FileColumns._ID, + COLUMN_BUCKET_ID, + COLUMN_BUCKET_DISPLAY_NAME, + MediaStore.MediaColumns.MIME_TYPE}; + + // === 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_29 = + "(" + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?" + + " OR " + + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?)" + + " AND " + MediaStore.MediaColumns.SIZE + ">0"; + 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 final String SELECTION_FOR_SINGLE_MEDIA_TYPE_29 = + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?" + + " AND " + MediaStore.MediaColumns.SIZE + ">0"; + + private static String[] getSelectionArgsForSingleMediaType(int mediaType) { + return new String[]{String.valueOf(mediaType)}; + } + // ============================================= + + // === params for showSingleMediaType: true === + private static final String SELECTION_FOR_SINGLE_MEDIA_GIF_TYPE = + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?" + + " AND " + MediaStore.MediaColumns.SIZE + ">0" + + " AND " + MediaStore.MediaColumns.MIME_TYPE + "=?" + + ") GROUP BY (bucket_id"; + private static final String SELECTION_FOR_SINGLE_MEDIA_GIF_TYPE_29 = + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?" + + " AND " + MediaStore.MediaColumns.SIZE + ">0" + + " AND " + MediaStore.MediaColumns.MIME_TYPE + "=?"; + + private static String[] getSelectionArgsForSingleMediaGifType(int mediaType) { + return new String[]{String.valueOf(mediaType), "image/gif"}; + } + // ============================================= + + private static final String BUCKET_ORDER_BY = "datetaken DESC"; + + private AlbumLoader(Context context, String selection, String[] selectionArgs) { + super( + context, + QUERY_URI, + beforeAndroidTen() ? PROJECTION : PROJECTION_29, + selection, + selectionArgs, + BUCKET_ORDER_BY + ); + } + + public static CursorLoader newInstance(Context context) { + String selection; + String[] selectionArgs; + if (SelectionSpec.getInstance().onlyShowGif()) { + selection = beforeAndroidTen() + ? SELECTION_FOR_SINGLE_MEDIA_GIF_TYPE : SELECTION_FOR_SINGLE_MEDIA_GIF_TYPE_29; + selectionArgs = getSelectionArgsForSingleMediaGifType( + MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE); + } else if (SelectionSpec.getInstance().onlyShowImages()) { + selection = beforeAndroidTen() + ? SELECTION_FOR_SINGLE_MEDIA_TYPE : SELECTION_FOR_SINGLE_MEDIA_TYPE_29; + selectionArgs = getSelectionArgsForSingleMediaType( + MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE); + } else if (SelectionSpec.getInstance().onlyShowVideos()) { + selection = beforeAndroidTen() + ? SELECTION_FOR_SINGLE_MEDIA_TYPE : SELECTION_FOR_SINGLE_MEDIA_TYPE_29; + selectionArgs = getSelectionArgsForSingleMediaType( + MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO); + } else { + selection = beforeAndroidTen() ? SELECTION : SELECTION_29; + selectionArgs = SELECTION_ARGS; + } + return new AlbumLoader(context, selection, selectionArgs); + } + + @Override + public Cursor loadInBackground() { + Cursor albums = super.loadInBackground(); + MatrixCursor allAlbum = new MatrixCursor(COLUMNS); + + if (beforeAndroidTen()) { + int totalCount = 0; + Uri allAlbumCoverUri = null; + MatrixCursor otherAlbums = new MatrixCursor(COLUMNS); + if (albums != null) { + while (albums.moveToNext()) { + long fileId = albums.getLong( + albums.getColumnIndex(MediaStore.Files.FileColumns._ID)); + long bucketId = albums.getLong( + albums.getColumnIndex(COLUMN_BUCKET_ID)); + String bucketDisplayName = albums.getString( + albums.getColumnIndex(COLUMN_BUCKET_DISPLAY_NAME)); + String mimeType = albums.getString( + albums.getColumnIndex(MediaStore.MediaColumns.MIME_TYPE)); + Uri uri = getUri(albums); + int count = albums.getInt(albums.getColumnIndex(COLUMN_COUNT)); + + otherAlbums.addRow(new String[]{ + Long.toString(fileId), + Long.toString(bucketId), bucketDisplayName, mimeType, uri.toString(), + String.valueOf(count)}); + totalCount += count; + } + if (albums.moveToFirst()) { + allAlbumCoverUri = getUri(albums); + } + } + + allAlbum.addRow(new String[]{ + Album.ALBUM_ID_ALL, Album.ALBUM_ID_ALL, Album.ALBUM_NAME_ALL, null, + allAlbumCoverUri == null ? null : allAlbumCoverUri.toString(), + String.valueOf(totalCount)}); + + return new MergeCursor(new Cursor[]{allAlbum, otherAlbums}); + } else { + int totalCount = 0; + Uri allAlbumCoverUri = null; + + // Pseudo GROUP BY + Map countMap = new HashMap<>(); + if (albums != null) { + while (albums.moveToNext()) { + long bucketId = albums.getLong(albums.getColumnIndex(COLUMN_BUCKET_ID)); + + Long count = countMap.get(bucketId); + if (count == null) { + count = 1L; + } else { + count++; + } + countMap.put(bucketId, count); + } + } + + MatrixCursor otherAlbums = new MatrixCursor(COLUMNS); + if (albums != null) { + if (albums.moveToFirst()) { + allAlbumCoverUri = getUri(albums); + + Set done = new HashSet<>(); + + do { + long bucketId = albums.getLong(albums.getColumnIndex(COLUMN_BUCKET_ID)); + + if (done.contains(bucketId)) { + continue; + } + + long fileId = albums.getLong( + albums.getColumnIndex(MediaStore.Files.FileColumns._ID)); + String bucketDisplayName = albums.getString( + albums.getColumnIndex(COLUMN_BUCKET_DISPLAY_NAME)); + String mimeType = albums.getString( + albums.getColumnIndex(MediaStore.MediaColumns.MIME_TYPE)); + Uri uri = getUri(albums); + long count = countMap.get(bucketId); + + otherAlbums.addRow(new String[]{ + Long.toString(fileId), + Long.toString(bucketId), + bucketDisplayName, + mimeType, + uri.toString(), + String.valueOf(count)}); + done.add(bucketId); + + totalCount += count; + } while (albums.moveToNext()); + } + } + + allAlbum.addRow(new String[]{ + Album.ALBUM_ID_ALL, + Album.ALBUM_ID_ALL, Album.ALBUM_NAME_ALL, null, + allAlbumCoverUri == null ? null : allAlbumCoverUri.toString(), + String.valueOf(totalCount)}); + + return new MergeCursor(new Cursor[]{allAlbum, otherAlbums}); + } + } + + private static Uri getUri(Cursor cursor) { + long id = cursor.getLong(cursor.getColumnIndex(MediaStore.Files.FileColumns._ID)); + String mimeType = cursor.getString( + cursor.getColumnIndex(MediaStore.MediaColumns.MIME_TYPE)); + Uri contentUri; + + if (MimeType.isImage(mimeType)) { + contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; + } else if (MimeType.isVideo(mimeType)) { + contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; + } else { + // ? + contentUri = MediaStore.Files.getContentUri("external"); + } + + Uri uri = ContentUris.withAppendedId(contentUri, id); + return uri; + } + + @Override + public void onContentChanged() { + // FIXME a dirty way to fix loading multiple times + } + + /** + * @return 是否是 Android 10 (Q) 之前的版本 + */ + private static boolean beforeAndroidTen() { + return android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.Q; + } +} \ No newline at end of file diff --git a/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/loader/AlbumMediaLoader.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/loader/AlbumMediaLoader.java new file mode 100644 index 0000000..7bba0d6 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/loader/AlbumMediaLoader.java @@ -0,0 +1,197 @@ +/* + * 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 androidx.loader.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}; + } + // =============================================================== + + // === params for album ALL && showSingleMediaType: true && MineType=="image/gif" + private static final String SELECTION_ALL_FOR_GIF = + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?" + + " AND " + + MediaStore.MediaColumns.MIME_TYPE + "=?" + + " AND " + MediaStore.MediaColumns.SIZE + ">0"; + + private static String[] getSelectionArgsForGifType(int mediaType) { + return new String[]{String.valueOf(mediaType), "image/gif"}; + } + // =============================================================== + + // === params for ordinary album && showSingleMediaType: true && MineType=="image/gif" === + private static final String SELECTION_ALBUM_FOR_GIF = + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?" + + " AND " + + " bucket_id=?" + + " AND " + + MediaStore.MediaColumns.MIME_TYPE + "=?" + + " AND " + MediaStore.MediaColumns.SIZE + ">0"; + + private static String[] getSelectionAlbumArgsForGifType(int mediaType, String albumId) { + return new String[]{String.valueOf(mediaType), albumId, "image/gif"}; + } + // =============================================================== + + 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().onlyShowGif()) { + selection = SELECTION_ALL_FOR_GIF; + selectionArgs = getSelectionArgsForGifType( + MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE); + } else 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().onlyShowGif()) { + selection = SELECTION_ALBUM_FOR_GIF; + selectionArgs = + getSelectionAlbumArgsForGifType( + MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE, album.getId()); + } 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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/model/AlbumCollection.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/model/AlbumCollection.java new file mode 100644 index 0000000..ceabef6 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/model/AlbumCollection.java @@ -0,0 +1,114 @@ +/* + * 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 androidx.fragment.app.FragmentActivity; +import androidx.loader.app.LoaderManager; +import androidx.loader.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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/model/AlbumMediaCollection.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/model/AlbumMediaCollection.java new file mode 100644 index 0000000..fa25939 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/model/AlbumMediaCollection.java @@ -0,0 +1,107 @@ +/* + * 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 androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.FragmentActivity; +import androidx.loader.app.LoaderManager; +import androidx.loader.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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/model/SelectedItemCollection.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/model/SelectedItemCollection.java new file mode 100644 index 0000000..7fdf690 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/model/SelectedItemCollection.java @@ -0,0 +1,256 @@ +/* + * 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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/AlbumPreviewActivity.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/AlbumPreviewActivity.java new file mode 100644 index 0000000..01c82e3 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/AlbumPreviewActivity.java @@ -0,0 +1,97 @@ +/* + * 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 androidx.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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/BasePreviewActivity.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/BasePreviewActivity.java new file mode 100644 index 0000000..770dea9 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/BasePreviewActivity.java @@ -0,0 +1,358 @@ +/* + * 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 androidx.annotation.Nullable; +import androidx.viewpager.widget.ViewPager; +import androidx.interpolator.view.animation.FastOutSlowInInterpolator; +import androidx.appcompat.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_apply_default); + mButtonApply.setEnabled(false); + } else if (selectedCount == 1 && mSpec.singleSelectionModeEnabled()) { + mButtonApply.setText(R.string.button_apply_default); + mButtonApply.setEnabled(true); + } else { + mButtonApply.setEnabled(true); + mButtonApply.setText(getString(R.string.button_apply, 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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/MediaSelectionFragment.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/MediaSelectionFragment.java new file mode 100644 index 0000000..86c46e2 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/MediaSelectionFragment.java @@ -0,0 +1,159 @@ +/* + * 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 androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/PreviewItemFragment.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/PreviewItemFragment.java new file mode 100644 index 0000000..47240b6 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/PreviewItemFragment.java @@ -0,0 +1,129 @@ +/* + * 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 androidx.annotation.Nullable; +import androidx.fragment.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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/SelectedPreviewActivity.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/SelectedPreviewActivity.java new file mode 100644 index 0000000..8b934c7 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/SelectedPreviewActivity.java @@ -0,0 +1,51 @@ +/* + * 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 androidx.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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/AlbumMediaAdapter.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/AlbumMediaAdapter.java new file mode 100644 index 0000000..f0eb971 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/AlbumMediaAdapter.java @@ -0,0 +1,300 @@ +/* + * 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 androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.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 (mSelectionSpec.showPreview) { + if (mOnMediaClickListener != null) { + mOnMediaClickListener.onMediaClick(null, item, holder.getAdapterPosition()); + } + } else { + updateSelectedItem(item, holder); + } + } + + @Override + public void onCheckViewClicked(CheckView checkView, Item item, RecyclerView.ViewHolder holder) { + updateSelectedItem(item, holder); + } + + private void updateSelectedItem(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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/AlbumsAdapter.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/AlbumsAdapter.java new file mode 100644 index 0000000..8e809c9 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/AlbumsAdapter.java @@ -0,0 +1,71 @@ +/* + * 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.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; + +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), album.getCoverUri()); + } +} diff --git a/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/PreviewPagerAdapter.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/PreviewPagerAdapter.java new file mode 100644 index 0000000..b75abc1 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/PreviewPagerAdapter.java @@ -0,0 +1,70 @@ +/* + * 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 androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/RecyclerViewCursorAdapter.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/RecyclerViewCursorAdapter.java new file mode 100644 index 0000000..48203b0 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/RecyclerViewCursorAdapter.java @@ -0,0 +1,105 @@ +/* + * 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 androidx.recyclerview.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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/AlbumsSpinner.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/AlbumsSpinner.java new file mode 100644 index 0000000..92dfa27 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/AlbumsSpinner.java @@ -0,0 +1,129 @@ +/* + * 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 androidx.annotation.NonNull; +import androidx.appcompat.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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/CheckRadioView.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/CheckRadioView.java new file mode 100644 index 0000000..1d71b72 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/CheckRadioView.java @@ -0,0 +1,60 @@ +package com.zhihu.matisse.internal.ui.widget; + +import android.content.Context; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; +import androidx.core.content.res.ResourcesCompat; +import androidx.appcompat.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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/CheckView.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/CheckView.java new file mode 100644 index 0000000..7407325 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/CheckView.java @@ -0,0 +1,229 @@ +/* + * 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 androidx.core.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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/IncapableDialog.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/IncapableDialog.java new file mode 100644 index 0000000..a1b7201 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/IncapableDialog.java @@ -0,0 +1,64 @@ +/* + * 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 androidx.annotation.NonNull; +import androidx.fragment.app.DialogFragment; +import androidx.appcompat.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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/MediaGrid.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/MediaGrid.java new file mode 100644 index 0000000..0abb367 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/MediaGrid.java @@ -0,0 +1,161 @@ +/* + * 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 androidx.recyclerview.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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/MediaGridInset.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/MediaGridInset.java new file mode 100644 index 0000000..dca609c --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/MediaGridInset.java @@ -0,0 +1,60 @@ +/* + * 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 androidx.recyclerview.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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/PreviewViewPager.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/PreviewViewPager.java new file mode 100644 index 0000000..b3e66c3 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/PreviewViewPager.java @@ -0,0 +1,38 @@ +/* + * 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 androidx.viewpager.widget.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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/RoundedRectangleImageView.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/RoundedRectangleImageView.java new file mode 100644 index 0000000..b1a5220 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/RoundedRectangleImageView.java @@ -0,0 +1,65 @@ +/* + * 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 androidx.appcompat.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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/SquareFrameLayout.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/SquareFrameLayout.java new file mode 100644 index 0000000..1f95518 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/SquareFrameLayout.java @@ -0,0 +1,36 @@ +/* + * 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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/utils/ExifInterfaceCompat.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/utils/ExifInterfaceCompat.java new file mode 100644 index 0000000..b2be0e4 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/utils/ExifInterfaceCompat.java @@ -0,0 +1,131 @@ +/* + * 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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/utils/MediaStoreCompat.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/utils/MediaStoreCompat.java new file mode 100644 index 0000000..592c77e --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/utils/MediaStoreCompat.java @@ -0,0 +1,145 @@ +/* + * 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 androidx.fragment.app.Fragment; +import androidx.core.content.FileProvider; +import androidx.core.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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/utils/PathUtils.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/utils/PathUtils.java new file mode 100644 index 0000000..de64322 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/utils/PathUtils.java @@ -0,0 +1,135 @@ +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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/utils/PhotoMetadataUtils.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/utils/PhotoMetadataUtils.java new file mode 100644 index 0000000..59c1c8c --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/utils/PhotoMetadataUtils.java @@ -0,0 +1,178 @@ +/* + * 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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/utils/Platform.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/utils/Platform.java new file mode 100644 index 0000000..df41989 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/utils/Platform.java @@ -0,0 +1,16 @@ +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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/utils/SingleMediaScanner.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/utils/SingleMediaScanner.java new file mode 100644 index 0000000..81370df --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/utils/SingleMediaScanner.java @@ -0,0 +1,44 @@ +package com.zhihu.matisse.internal.utils; + +import android.content.Context; +import android.media.MediaScannerConnection; +import android.net.Uri; + +/** + * @author 工藤 + * @email gougou@16fan.com + * create at 2018年10月23日12:17:59 + * description:媒体扫描 + */ +public class SingleMediaScanner implements MediaScannerConnection.MediaScannerConnectionClient { + + private MediaScannerConnection mMsc; + private String mPath; + private ScanListener mListener; + + public interface ScanListener { + + /** + * scan finish + */ + void onScanFinish(); + } + + public SingleMediaScanner(Context context, String mPath, ScanListener mListener) { + this.mPath = mPath; + this.mListener = mListener; + this.mMsc = new MediaScannerConnection(context, this); + this.mMsc.connect(); + } + + @Override public void onMediaScannerConnected() { + mMsc.scanFile(mPath, null); + } + + @Override public void onScanCompleted(String mPath, Uri mUri) { + mMsc.disconnect(); + if (mListener != null) { + mListener.onScanFinish(); + } + } +} diff --git a/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/utils/UIUtils.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/utils/UIUtils.java new file mode 100644 index 0000000..129b599 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/internal/utils/UIUtils.java @@ -0,0 +1,32 @@ +/* + * 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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/listener/OnCheckedListener.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/listener/OnCheckedListener.java new file mode 100644 index 0000000..4a0ebae --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/listener/OnCheckedListener.java @@ -0,0 +1,9 @@ +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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/listener/OnFragmentInteractionListener.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/listener/OnFragmentInteractionListener.java new file mode 100644 index 0000000..79f5536 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/listener/OnFragmentInteractionListener.java @@ -0,0 +1,11 @@ +package com.zhihu.matisse.listener; + +/** + * PreViewItemFragment 和 BasePreViewActivity 通信的接口 ,为了方便拿到 ImageViewTouch 的点击事件 + */ +public interface OnFragmentInteractionListener { + /** + * ImageViewTouch 被点击了 + */ + void onClick(); +} diff --git a/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/listener/OnSelectedListener.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/listener/OnSelectedListener.java new file mode 100644 index 0000000..b7d6d22 --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/listener/OnSelectedListener.java @@ -0,0 +1,30 @@ +/* + * 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 androidx.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/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/ui/MatisseActivity.java b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/ui/MatisseActivity.java new file mode 100644 index 0000000..662379a --- /dev/null +++ b/coalMiningApp/matisse/src/main/java/com/zhihu/matisse/ui/MatisseActivity.java @@ -0,0 +1,437 @@ +/* + * 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 androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; + +import android.util.Log; +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 com.zhihu.matisse.internal.utils.SingleMediaScanner; +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); + + new SingleMediaScanner(this.getApplicationContext(), path, new SingleMediaScanner.ScanListener() { + @Override public void onScanFinish() { + Log.i("SingleMediaScanner", "scan finish!"); + } + }); + finish(); + } + } + + private void updateBottomToolbar() { + + int selectedCount = mSelectedCollection.count(); + if (selectedCount == 0) { + mButtonPreview.setEnabled(false); + mButtonApply.setEnabled(false); + mButtonApply.setText(getString(R.string.button_apply_default)); + } else if (selectedCount == 1 && mSpec.singleSelectionModeEnabled()) { + mButtonPreview.setEnabled(true); + mButtonApply.setText(R.string.button_apply_default); + mButtonApply.setEnabled(true); + } else { + mButtonPreview.setEnabled(true); + mButtonApply.setEnabled(true); + mButtonApply.setText(getString(R.string.button_apply, 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/coalMiningApp/matisse/src/main/res/color/dracula_bottom_toolbar_apply.xml b/coalMiningApp/matisse/src/main/res/color/dracula_bottom_toolbar_apply.xml new file mode 100644 index 0000000..84e13af --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/color/dracula_bottom_toolbar_apply.xml @@ -0,0 +1,21 @@ + + + + + + \ No newline at end of file diff --git a/coalMiningApp/matisse/src/main/res/color/dracula_bottom_toolbar_preview.xml b/coalMiningApp/matisse/src/main/res/color/dracula_bottom_toolbar_preview.xml new file mode 100644 index 0000000..56e04b7 --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/color/dracula_bottom_toolbar_preview.xml @@ -0,0 +1,21 @@ + + + + + + \ No newline at end of file diff --git a/coalMiningApp/matisse/src/main/res/color/dracula_preview_bottom_toolbar_apply.xml b/coalMiningApp/matisse/src/main/res/color/dracula_preview_bottom_toolbar_apply.xml new file mode 100644 index 0000000..9920c27 --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/color/dracula_preview_bottom_toolbar_apply.xml @@ -0,0 +1,21 @@ + + + + + + \ No newline at end of file diff --git a/coalMiningApp/matisse/src/main/res/color/zhihu_bottom_toolbar_apply.xml b/coalMiningApp/matisse/src/main/res/color/zhihu_bottom_toolbar_apply.xml new file mode 100644 index 0000000..d12c968 --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/color/zhihu_bottom_toolbar_apply.xml @@ -0,0 +1,21 @@ + + + + + + \ No newline at end of file diff --git a/coalMiningApp/matisse/src/main/res/color/zhihu_bottom_toolbar_preview.xml b/coalMiningApp/matisse/src/main/res/color/zhihu_bottom_toolbar_preview.xml new file mode 100644 index 0000000..fef8d16 --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/color/zhihu_bottom_toolbar_preview.xml @@ -0,0 +1,21 @@ + + + + + + \ No newline at end of file diff --git a/coalMiningApp/matisse/src/main/res/color/zhihu_preview_bottom_toolbar_apply.xml b/coalMiningApp/matisse/src/main/res/color/zhihu_preview_bottom_toolbar_apply.xml new file mode 100644 index 0000000..0bec454 --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/color/zhihu_preview_bottom_toolbar_apply.xml @@ -0,0 +1,21 @@ + + + + + + diff --git a/coalMiningApp/matisse/src/main/res/drawable-hdpi/ic_arrow_drop_down_white_24dp.png b/coalMiningApp/matisse/src/main/res/drawable-hdpi/ic_arrow_drop_down_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..4c6076df77463404d7163c9929bad5798576c49b GIT binary patch literal 123 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K;lc$Sgh)3t!GrM^i6gXHN+!Ft< zyz%6wgzzGf8m{hg<~baK7i~0n1e^UrcB-xUbawM9)9}#zn5)@-SM$qEFA7|Y7jyVu Ve}1-8%O{{|44$rjF6*2UngF%-Cs62;P z;rt^PnzR4-B~3VNI!Vkwpm#}DQ`QtoT{RCjhCut7rDpeTegIm<;OXk;vd$@?2>|#_ BI?Vt8 literal 0 HcmV?d00001 diff --git a/coalMiningApp/matisse/src/main/res/drawable-hdpi/ic_empty_dracula.png b/coalMiningApp/matisse/src/main/res/drawable-hdpi/ic_empty_dracula.png new file mode 100644 index 0000000000000000000000000000000000000000..0920df470690bbbc7b20e2f8b3cc11d05d52c3fc GIT binary patch literal 5911 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 literal 0 HcmV?d00001 diff --git a/coalMiningApp/matisse/src/main/res/drawable-hdpi/ic_empty_zhihu.png b/coalMiningApp/matisse/src/main/res/drawable-hdpi/ic_empty_zhihu.png new file mode 100644 index 0000000000000000000000000000000000000000..86ffe1cda6b9b98d715e1f670a2f99aeed337070 GIT binary patch literal 5785 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 literal 0 HcmV?d00001 diff --git a/coalMiningApp/matisse/src/main/res/drawable-hdpi/ic_gif.png b/coalMiningApp/matisse/src/main/res/drawable-hdpi/ic_gif.png new file mode 100644 index 0000000000000000000000000000000000000000..d4085f56fb084eba0112bb70017881ba618fa333 GIT binary patch literal 929 zcmeAS@N?(olHy`uVBq!ia0vp^20$#!!3-pCzmtyzQY`6?zK#qG8~eHcB(gFvFa`wp zgt!95NdiJbLNYQkj*gBwIXUI!H#avQA0Ln_A|fIt zCMGE>n3z~uS=rdwxVpO9+1dH{`1t$#2L=WP2M4cQ zxiTs$YSpS$DJd!G>FF668QIy{rKP1?wrtt9ZChDc+4k+*Crp?CH00#TlR%Sa&YU@W z_U!rd=Pz8i@XD1d%a<=-x^(Hfb?Y{4*syi$R-l$0J9g~ey?Y-R96WgN>eZ{)uV24; z^X9Evw?2RVeCN&`Ao>0K_lFN3K7Rc8>C>mr!Qdqryng)}DE0R3+jsBYefaR<%a<>I z|Ni~C@dz zliG_JVcVjnne^xXc80)>&F$Iu56{`z{!`)|gSaARbLW;< z4zqYx^fo3%=q+PDZZu_)L}uK9rsch#{=ST6oLn9C%JCzUnT@JhLJMO8&xs>^N*mN% zidKC+d(&~(4X^l9{z)}@+8V4foohDwRo02AD5+*{ffSutjI)4w)OD34HG75WN}0rT%0iZyWoyv zH=TFgwcrdmBv|+CK=~(4j+F{)5_~;R{9&Qy;ZR-nEP2X!Y}OqFikkW%~6@vd$@?2>?<#oM-?5 literal 0 HcmV?d00001 diff --git a/coalMiningApp/matisse/src/main/res/drawable-hdpi/ic_play_circle_outline_white_48dp.png b/coalMiningApp/matisse/src/main/res/drawable-hdpi/ic_play_circle_outline_white_48dp.png new file mode 100644 index 0000000000000000000000000000000000000000..6e1b578c54d13ceabffc2d6f49a383bc73605988 GIT binary patch literal 1023 zcmV0zV6u|K(L}#j#NlM5x;x=T{UGWVyM6uO@Y=mavGW`M?Mv;Vk1VIByAc4}n(2A*U z3=>39h#Cx`NLT5qBxa@2VKTTVm^*|2F3)|K+?O-=N$FyK=L`Jd+ugiT!=ubL>nt$F6^>#W8-sqjxydRXVfJ`Mfo~2z=pxJ1h^tDG{(}p;#A_O{ z$_4j9$N8Nk?sLp#&^11hRE0q|L1|{#-wqELCQlEYq)5?84|#@JdAN#x|i1x`yp%S}_Uc5VP2R)C3*p6LyYqFm_Uf z?)X8A*vo2l64Xi&zhC19UBbSUvlvIy!6ttF@q%6>ywE%ATXoV&YKWI{f-d5B2NN>? z@RK@e9KXKkpk>6nh{qtnyz=cZ%MM~GDyW+pqJW7Eg1?ljyN#%l3lF-9D3gg5gmQIl z>>_T22dyF|F)@R*tD8o=2n)*KAx^1+G^;y{_{@>upgdv+qYF~3u7wifa&XWX;(w^yq^WtLsH<1qYQ8o%$ff>bel6 z;2;l?(g!J4mqzUUmqA0xg50ibBl*f)Uet5RFKU;!{ZNA2-uZ)ZL-}BwjrY^Bs1J%< zmCPf=NN~^<#0OQ7tV;jm`a^KgQ9Q(HWzdHE*AK%h#FQ#1dQ~zrh!sp&Pyw;4c!eEO zz2;XC*P~wYtB6}sL5fw$j37L^!h;M&#QX5?U5Zu7wDS@17!wuLkKbKP@F-R#GlAc^ z=pe%?qRI)Ue@dUBW?#^8f-c~N^RHaXc)&Kcffd&*&b zkRi((Y*og|Dj$Or)Uf?Qrs1Q7x+K`)Hf=F~vqt#{bva#04qvi7r`|5poTVk?jylH- z73w`Dlk|8h#U%SH@sI)o^wLF|G+p#EK!Hb;*xx-4yE(ucq(V|DvGR literal 0 HcmV?d00001 diff --git a/coalMiningApp/matisse/src/main/res/drawable-hdpi/ic_preview_radio_off.webp b/coalMiningApp/matisse/src/main/res/drawable-hdpi/ic_preview_radio_off.webp new file mode 100644 index 0000000000000000000000000000000000000000..80930b9a3851cd44287fc37cd9a93d090d5cde81 GIT binary patch literal 290 zcmV+-0p0#mNk&E*0RRA3MM6+kP&iBt0RR9mAHW9?2QmNiKmQEdMp7KS>@hzx1k?or z06c&P7@={);>Csy0DvD6z+eUNFaUxG0Vr?~Ns=PXF*DgNEx;IvhhPL~MI?WL$p}xGfHxQEfZJO2EZ#sT(E~K{ zi3WJ03OK`W3QwTwfk8ep0Q~~gUsVJ14isNi0Q(O}zA6EJYQ5^grr)AJk?Ol#K&Ah# o>iU0Nk&FW0RRA3MM6+kP&iCJ0RR9mAHW9?FERh~KmUv)NopHq7SGQkuYkEA z01yEpK!pXk;PGOi!2tm9BLM)11`8130E7$y6bKF?Nm8UfX2xgOFaIX@U|&H*{~5S# zq-e6UOb4AuXosNemz(+Cmc9&hg0%av!>3D+YGL!`fNvA-dUD|emt@EDhjo+ZP-Rh+ zRm01=#v|X>Eq~X(Hu&}1N_I80MyFW2#FI5>EocBnPX~A-KqD#r0+Z!Mdo||T7FL>o zZz^@bJC+poKP-NIC@Fpeoq`WgOA2Rpm_tc5@Ci!b=}YR_rI+MCfwBh%NyTs9eubm~ z=vSbU)N(*8sREWekV(28*;P^o+zk*(GDl`4MSyX(uXE$(KE-__r|mdKI;Vst078Ep6aWAK literal 0 HcmV?d00001 diff --git a/coalMiningApp/matisse/src/main/res/drawable-mdpi/ic_check_white_18dp.png b/coalMiningApp/matisse/src/main/res/drawable-mdpi/ic_check_white_18dp.png new file mode 100644 index 0000000000000000000000000000000000000000..ad1484767f791343581dfcdd35cfca4d0962c280 GIT binary patch literal 146 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 P2`4eoG0`s9d>Z{9WSgOK literal 0 HcmV?d00001 diff --git a/coalMiningApp/matisse/src/main/res/drawable-mdpi/ic_empty_zhihu.png b/coalMiningApp/matisse/src/main/res/drawable-mdpi/ic_empty_zhihu.png new file mode 100644 index 0000000000000000000000000000000000000000..f5628eee45059291eb92e29053378c59fb391fb0 GIT binary patch literal 3843 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 E1Fvf!WdHyG literal 0 HcmV?d00001 diff --git a/coalMiningApp/matisse/src/main/res/drawable-mdpi/ic_gif.png b/coalMiningApp/matisse/src/main/res/drawable-mdpi/ic_gif.png new file mode 100644 index 0000000000000000000000000000000000000000..aeeb0d4353897d4728aa9489bbb8c53ad005c98f GIT binary patch literal 638 zcmeAS@N?(olHy`uVBq!ia0vp^3P3E(!3-pidHp{Mq*&4&eH|GXHuiJ>Nn{1`p9lDa zxB_Wp;O6FLZEbC3Wd#&uW@ct%W8>!L78Dc|7Z>N?-~citB_(BKWK>jCw6wHzb#)aL z6?JrUOifMA&CP+jY;0_toSfX<-90@${r&v|0|SGDgTunYVq;^Il9CDv3W|z~%F4ILxK7HoQnX_llUbt}K-Me>h-@d(i_3Cx&)@|6ZVfXIc z=gytGaN)wun>T;|{{8ahOCb5~-MbGTKK%Xr7f62j^5xsNZ{NRv2a-R);3pUWl>q@z z&Hw-Z`-90_a=2!;;4SwnA;uxZFzIM{fphE^Ct(TXz zb}yLbD-a@(qRDluDP-fRM@)w*|36n$J#eA%+3$%bQ}&&lYx&*a*omdKI;Vst0CDpou>b%7 literal 0 HcmV?d00001 diff --git a/coalMiningApp/matisse/src/main/res/drawable-mdpi/ic_play_circle_outline_white_48dp.png b/coalMiningApp/matisse/src/main/res/drawable-mdpi/ic_play_circle_outline_white_48dp.png new file mode 100644 index 0000000000000000000000000000000000000000..615b80d08543f8285c7ac5ffd66435bf0da1b7ff GIT binary patch literal 699 zcmV;s0!00ZP)9ER~}Ocb>nNr>2151>$#LL?rDP#4l7hMYi)F$bWnTZ;s2>AO;FAR7@pi(*JO z#wdzz)U=@XHOb~`;O1G)$1@Y!MZw>_4PNj!84~BgzknDs6sb_7NvFFeH7YEVC5B_0 z?FAF8ae<$6-ZS2NAk8KnY}%Aa^%9up2Vpgtixx=m8Ic>dSR_M|{_av_$g#~WA|>Ks z14Ha%z#$6^;{Ccs>KL%cP?$i1eT@HkOB^R)36{7AlOS#ne8Q;n0>?fkX<(FWfq9H? zq;W!Slmm=cL4hCF$h139M7D5( z0+v(lAO&}zf-D9HET_sNWp|*4WP$^hQ)Q8=JJ3Xu!2!#u(#VxN&_Vix1C~<_AniXD zcpW~_L{gyxwP+`b`cM86^`Bfpa`u2u6ZLJnjBHy2I*s?fB1`T-7P<9)6j)B9J?0L{ zcs=aSgFefy(*zyp)azmA@Byil@CpQ+M(gJoS;6rNjMD*gLDzy#qZN@BPuu~mgxoWU z6LBwTA?rAPffP-o!6;6Ijd6lpGU6T3<}eN-B*v&>%-X(ql`tAig*?s)#z!1mAkH4f zJp~e$cTSNO#x8x~zWgd7N8}jx`B>#S28>+>!+w2_Q$pmH9r9#JGtga{EP2Y@Vdyx0 z(SCr;aZOm4%=YpVD#-?IY+9@{()*9VXRLCDpHo)!skHK+2t{RV2URfJy|Ab$V=002ovPDHLkV1oZnH8lVL literal 0 HcmV?d00001 diff --git a/coalMiningApp/matisse/src/main/res/drawable-mdpi/ic_preview_radio_off.webp b/coalMiningApp/matisse/src/main/res/drawable-mdpi/ic_preview_radio_off.webp new file mode 100644 index 0000000000000000000000000000000000000000..1a8f6c181bd65a6bf17999e7e8310f9e4fcc1367 GIT binary patch literal 410 zcmV;L0cHMDNk&GJ0RRA3MM6+kP&iD60RR9mFTe{BM=}5NKmQEdMpB%+fn#`vKsX@? z5k$d`3}S%*gbW~~f&g9sKVB3h7z@UQj0S-K2*5A^z(FKQiqywU&&=dsW6$1hzk!JU zGjQ9sQQUFU35u*YU>?b^Ih?QW_w{_(3<*M!O}ppMiRW(0Lavha?dO5p+WYfpdHH$b zvW&cDe*6XCn0w61JoSE9&Cc=VI;ickEz-1Tms{5{zQ(!vwFd3G7!JhU-rDnZkIG)3 zYRsZO*-O{U-2Cxb!3(R8`60JjjiP%GPxN=A$0%KzS;8Bo8B6vie)j1Rfd0de5&&4U z(JKUD#kQ>hWH(lXK(L-$225;n9V#_jHvv0#4+Mi9W`~61tP7Wp<1iWcK;m$T`FMv7 zF>N8hmiRUYVp@cX%bN~oVrmr965shsOoc)U;=8_yDOE^Hd~dzzZ}guq(NajH_Y=Jz z>it|ENBTI`=K*=1(dRK)o_w%nOIaQ^^BBqVyu6Oc>y*3>%ImDWj?4Q5bszHIK1be1 E0d``_;{X5v literal 0 HcmV?d00001 diff --git a/coalMiningApp/matisse/src/main/res/drawable-mdpi/ic_preview_radio_on.webp b/coalMiningApp/matisse/src/main/res/drawable-mdpi/ic_preview_radio_on.webp new file mode 100644 index 0000000000000000000000000000000000000000..b336c9c6ea2b9d952c9516bd8c580ca0feed8c41 GIT binary patch literal 486 zcmVMNk&HA0RRA3MM6+kP&iD|0RR9mFTe{Bk1_xAKmUr`wsC_e`+C3M1;Pcx zNDwLvVW2?R5P(qtgoFkGOc({=W1*oUBVr@sK`7`j1ONbtFaQ7!+elKRxqD_lhG(YD zKfUg~`S}DQ`maE3+h|!~cf;uQ25ClXk#CRZ*Xw-T=8Km6iq5)vI4>U6y7SAZm0g?y zmrQ*;h)zz4QxvGAyK_Ha*Hy@fR@IB6Mp-?5A5})vLAyPeMy2l?pQ|SMGNF1FiU;AW zWBc7&719q~=(1K)be)S5^DF5gr4h+c)EH8a(3)`V;~Dqk z?cshuY~#LX_`xNxunbA_jb8C~gm=;73rHjrkpxuT|yf8yQY%TCZ(D(|cLV+fU-@C}+r4qHi zb?uExOCXVN;iU~wiJcO$*P6CRcxeJuw%WD@Qd8h?Ji|)^pmNZ*1CSa3hw}?wY6F$K zw%vhL8#uh|oBhQ82y%-IAF{U-dpoqZb9+DfgP+>R0rNOxAIFU1B>hcf7Kcf8fq9%a c&m-n}$~+I6=UMwaZeAxC*CBtdbFAwq0h#XQv;Y7A literal 0 HcmV?d00001 diff --git a/coalMiningApp/matisse/src/main/res/drawable-xhdpi/ic_arrow_drop_down_white_24dp.png b/coalMiningApp/matisse/src/main/res/drawable-xhdpi/ic_arrow_drop_down_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..da239e4f4e0169d670679e8af8c86c5c4fffa7ca GIT binary patch literal 120 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 S42-GR13pM9NR*2i1^y4^lequ@ literal 0 HcmV?d00001 diff --git a/coalMiningApp/matisse/src/main/res/drawable-xhdpi/ic_empty_zhihu.png b/coalMiningApp/matisse/src/main/res/drawable-xhdpi/ic_empty_zhihu.png new file mode 100644 index 0000000000000000000000000000000000000000..c223b5691fede910722565a39c0ad54f5837da53 GIT binary patch literal 7977 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 ZPegCQZ-8fk{bz-}6yK=GR!W-%{}+D literal 0 HcmV?d00001 diff --git a/coalMiningApp/matisse/src/main/res/drawable-xhdpi/ic_gif.png b/coalMiningApp/matisse/src/main/res/drawable-xhdpi/ic_gif.png new file mode 100644 index 0000000000000000000000000000000000000000..ed2a70be64b73b78b3b11e2c2c288fca73fbffb7 GIT binary patch literal 993 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBN!3-pwrE*sTDVB6cUq=Rpjs4tz5?L7-7$XCG zLR^93xBwp?A4JOA+uP62&)3%%$Yo<=gwX+;_mM5k&%(n(a~{naR~_t zNl8h$xw)mKrDbJhm6eq>H8l+l4Rv*Ojg5_MZEYPL9qsMyJv}|gjvedm?VT`T0+4a? zWy;K%Gw02lH)qbA1q&7|TC`}%k|oQRFJG}@#p>0o*REZ=VZ(;4 zTeoi8wr%(B-G>h!e*XM9#DueF&z?JX?!tu&moHzwdiCn{>(_7Hx^?HyoqPB0ef;fq_(8Ti4v$+6oM!_Kwc3?(QBblCwitUF)5#!mHRKA3bDuul~^5kXZ`kN7D`Lk zJd)ICQxM1;VBFa>sz9FBzbv8UzPYGj*@Z@<6v z$4bWT`SFT~iH~yEGsl!Qt(doW(*^;i84r$U23%n&hk98JoMIUsRh&Mj8% z2h1F1j5_t*TIMVzj2(ja?h8)&@mDHeiYbOcebd2gIq?URa=z!cXmbZ4@dLcfJA|4-XR*BaeTePO!ug!n<`w7E z2uKFLX+KhUan<~?Re$Uqa=p5%m%P0<_0oO+NRP}_OMX?h1kF0Wf8JXE%#**C+`87a zW!=sV85+5}r$pR2*}Zz7>C?IS26F`Our-%y@V0#ubMLNWkW%|`^Ub>zPN3Z9>FVdQ I&MBb@02;-$F#rGn literal 0 HcmV?d00001 diff --git a/coalMiningApp/matisse/src/main/res/drawable-xhdpi/ic_play_circle_outline_white_48dp.png b/coalMiningApp/matisse/src/main/res/drawable-xhdpi/ic_play_circle_outline_white_48dp.png new file mode 100644 index 0000000000000000000000000000000000000000..516f6432693ac6d89901a2c9a0e76baa01045808 GIT binary patch literal 1379 zcmV-p1)TbcP)y%WEavn41Afhq;gFm$1qB5K1qI<@ z9`ziggS+%G$_J*H;sc}fafeGBq@F5Fm}dy*N@?H%0|e1eJ6lQ2lz<}Y>Eb=ECh257 zMbjHlPLd%s25F{jdIAz0;Vof!O)K$y2Q=}FFb&g~zko&DCJNmw%tyd3CWuOkrf36V z{1IRbowTxm||j7vx+SoqLZiixj;!&0rU8q?9$w0549MdTg*Os_>#YMY}V#CI6|v4+Q4hEy3wKrG9T?qw2~kgkktcr}I*2yX{zY~8sAG?A$p6Y(7& zQ)4ax37%oQjLF0OiEWs;d%$6Ak4WStpqv40`&|Rdd4n_+@YmLF#MKGklSX<)sarr2 zTN@_O!9$j-6WX!ubqOeD26U*$AJR%ifPPA=?RfuyQKV``fPPBzkzV=- zd_amR0`yagBTf1TOd%C30`yZVM*2L{0)9~hO#6f$1ej35PM$eG#2r!n5ceUiau3i? zNAody2Wd;_0S^?v$Zq-vTtYhJ7NDPwxMN7?BY&9FPe;f&Ziw*N)WV7NDDsxcf+L!2-4-rCmm(n~u0; z*fs$|Lo>E>K?9W2@qVCz-58gEGF~I4S%dMvT&E*$Ew)h- zZUKf?Y>z3!-+5!P#$wLHg5ns(+YpLsg)_Kcb^ zUwmDbB>_?#XHJd}%qJMf+f$Z?{pxWoPatc=X})#*YwHZ-WYbSg6fb{Q(aV?gk__-1 zx`Gz&^Cdl0MD_Z8377Emf-a8Iz-s0brJ{_QMkc^{Cx?ikzv9#$hLfc4J*z8UJ-^-lEkLxi*Tjv?SeYUq!6rD(`SL z!4-aB)=c>_Xq-))+*+~&F lGp`V!zd}GEpb$_9_#bazb~6%eta1PV002ovPDHLkV1nTeaFqZ6 literal 0 HcmV?d00001 diff --git a/coalMiningApp/matisse/src/main/res/drawable-xhdpi/ic_preview_radio_off.webp b/coalMiningApp/matisse/src/main/res/drawable-xhdpi/ic_preview_radio_off.webp new file mode 100644 index 0000000000000000000000000000000000000000..b13bb1bd8cd14e87284b293b92aac64266ee76c9 GIT binary patch literal 544 zcmV+*0^j{oNk&E(0ssJ4MM6+kP&iBs0ssInKfn(VmofkIKmQEdMp7L7%;Gcu2Zn=y z0|*8~AW)d#0F4a|!2rMuM{4fAeC^QZ@zz&B11VL~lfZzbYVQsrS7j5aURf~jZYS3I%Dq8sw8!tUb1^IBOrKK+`-WPy10;*;$?41>=+BTHoSk73Z( zq2xxp*5rWt$_>VUC*{7n&&Ubcp8F`f|G4eCc0O9+n%lq(nE~fLa)!q_JVMchsTDcc z0aJN~Lp)|iV|qAtUoO7MZ`%1RfXlca;KLs<#2ac2SqHYAJ<(48!S zz(`s~KzF$V0*$mZKzDZp0=cy0K=*hD0*SOFK==Lz0=~5PK=-XL`WgKu`UC0jTm5sR ze{S{f4fT6V|K8NUx7FVb{dY_M-Bf?Kwe^Neq^`H9=uH8uH~o{|MwN=*sIIrF>&^Ol iySm+=ZMW##O@CmwIbh&!HxAV8R&~4i5AAmK{|yKmKMGR- literal 0 HcmV?d00001 diff --git a/coalMiningApp/matisse/src/main/res/drawable-xhdpi/ic_preview_radio_on.webp b/coalMiningApp/matisse/src/main/res/drawable-xhdpi/ic_preview_radio_on.webp new file mode 100644 index 0000000000000000000000000000000000000000..632b2a7351067900bedf2bb3cc9ee67097f35e01 GIT binary patch literal 644 zcmV-~0(<>ZNk&F|0ssJ4MM6+kP&iC)0ssInKfn(V_c8zTKmUx|HgX(0Ic)x3;5#UQ z0R+P+iir&nfQ1KPK`;RL5lj@t!~-}m0GOCq2o{0>Yzzbf5CkCr000390YCvkw(Ycy z!_3Ug%&h(It9{>+zZW1&5&d`IMv|jU-yO@w1}5?ZM;ggWXS~{7KF01=K}RPYZ;|V* zf5HWN-LszcM4KBSiA_^`(TcavLII{7SH9~+QMw&2^%vWR4Hl*prriQDcmN}A6T6WsQiGcyaI>0RKy23j|3S`pDs@n# z`xGv)IzpX;ho1j^O-C;D=d_HVO97h1sPk0kQy(OM{Z z5zQV_$x$4x30y&pN(|zHgr+_#s=C?)>j)LiNn(JgV&79mEOu2foFpqa8~w~c zD8Zun;AGta0yEV1o0{Cv0yGe@V<6B1LM5RH3-k=|7_Wdp83^@N#Q;4GJnRk#WPs2@ zRTe&AVS>SQ`00I0#9;#yT=LH@g&*kne{BQWD@NdMgxBPa)Z@2t@ zgWYfWz;F7%Z?ne@{*6r;78w3DZh${>L literal 0 HcmV?d00001 diff --git a/coalMiningApp/matisse/src/main/res/drawable-xxhdpi/ic_arrow_drop_down_white_24dp.png b/coalMiningApp/matisse/src/main/res/drawable-xxhdpi/ic_arrow_drop_down_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..c19c19d2bd2709454a29d9140d5d0a1ff51302c4 GIT binary patch literal 152 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhaw;yqm)Lo)8Yz2eB#U?9M9(5ALd z&e6u>Lico@h_6j*yKfo-6){+xJ+uDO)G6!2y{HulII0e{ z{C)H>r(rG|rQ9*iWu-(!7^S%ERGKrPlsj}eGfKIAi#r=qJ>08@0j1o|iBfLsM1649 mREzVV^gVB!s3?k}zv~IfJrzvItflq<0000O!A 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 H=5PK7I&xEu literal 0 HcmV?d00001 diff --git a/coalMiningApp/matisse/src/main/res/drawable-xxhdpi/ic_gif.png b/coalMiningApp/matisse/src/main/res/drawable-xxhdpi/ic_gif.png new file mode 100644 index 0000000000000000000000000000000000000000..2803825a9d32f01a4edac4a58cb62ee3be3c356d GIT binary patch literal 1380 zcmeAS@N?(olHy`uVBq!ia0vp^2|#Sg!3-q-9lvJ^q*&4&eH|GXHuiJ>Nn~YUVB8&v>gp;gDgqf=T3R|fI{NzhMn*>F=H`Zmh9)K^R#sN__V!LrPKy>T za&d8ScX#*n^z`xZ@%Q&%ym;}_rAq??1A~Ku!@|O%qM~ABV-pe*Qd3h?Qc}{>(=#$M za&vPF3JQvfib_gKYHDh#s;U|q8k(D%+uGWCdV0FMyL)?kCrp?yY0{*bGiT15H}BlJ zbMxoVU$}7L`Sa(2HZEDR1Zc(DwQDzQ*syi$)-7AMY}>YN$BrGlckh1m=+VA?`wkyI zeDvti(_nD+>{*~Lpa~bi;Of<@cfjD@y?YNHJox(_7Iym|Zf?YnpHK7hfePoID)zkK=f_wV0t-@bkS{vE>j0R}&R{`?IFK*9h2 z|3k>{GJWR2XqZ|OTug5D*RwAqa>@fEWk>h8z&YK|p+b zJTMp&5)+evAUQcDB{ek-7@X;unVDHxS=re+xq11(P%SJhDlRT9D=RB6uc)l9sjaOA zCWHF=hK9zbrsn3Bme$tRwzl^6_KuFut}b9u_w;BiC|74-U|R3#;usQfc<+q#cwt9@ zcIPI|m`SRx%@G}3f}%QxOl?Wb*)D-D%3@bIx>&iTxVu^&CwO@W4x&4lxyYJC2Tbue7PO4w|H~ro_)q^f-(FAb$~{QFPrmt4D+C0RWv&-{FSVnE}fRRT(-vwo|eR5}`F9yssdJN}2ymzzA%uV>F! zIIn1bmVM8sA1caIx-Yp%t#zuM$iF~B zd7t(yS@^(N$=)@LX=cs|Z=!G3?dN?{CVb$A*5fNI1(J`XOv*oZ3C1TePTS^mXT!Bp zE*s~F22YOcs0+L9%@H>3V%@=)n0_WnfWcOvtX+8l@1bQDOtTc66D6^SRE=KKI1-8iU}DGC#9CiR+9k4evxhGHh9S`5M=Qg7u5)vKt-?lzE%&^D)}m zu}@%H-Wz+JaboMEr1H`%3=ucZ{5uK&gJ$sAy?#F}6wO8lXrC(pgza!kjO!35Ox7FfLw2aTP8z_a(yz@F`#h1!G3R^FUSBu{L z@pJN#qnmF}x?URn<9qj#zVJ!O$Gxwp?X%s@`@*W|lD)~ljlxo_+7Ccwqo=E%%Q~lo FCIBjUeenPQ literal 0 HcmV?d00001 diff --git a/coalMiningApp/matisse/src/main/res/drawable-xxhdpi/ic_play_circle_outline_white_48dp.png b/coalMiningApp/matisse/src/main/res/drawable-xxhdpi/ic_play_circle_outline_white_48dp.png new file mode 100644 index 0000000000000000000000000000000000000000..0311f899dd60c1856b10b4af459409309444aad9 GIT binary patch literal 2145 zcmV-n2%h(eP)4O>k|04P4={^H zR0aP#;guS6}b11-zrxUTURjDxM=dLD=N zoXbEBq{(GJQ!tJ;l^${#rQTJbI6ypbEZJ3DeHDu?A=>=MiY(FN#JA`b7R-iaPBDv=K zBWV{^4gyW%29kbaI)Pe{`Ts%#{>NMgiCU2@*9p{z&@Ln&U=#wmIJGV$JBkfd&2QL^QL7Qi$*Ij`9J^8OFD}qVBpn!y zK#opr2a*lN1^ODh2_Dl45Ag&k4;i)C~6}v6|0`*|G2cs9r>8b6*?ts5QgV=4*4CM6G+OfOjC(slmb2I}v zJ+*mACKVoNDR#reGy^$3wHPDVH5VSJP5ur=Gmzs`JA>WY!UMgH-FDqTj!&%vyKRLB z+JoI@-9U~{?G5a97ar&&b}MxQIX<;j*qtamP(OAHbOSj)wI=K?6dq_0yIHz{9G}{3 z>;?)Cl*F!DH<05~n}Xd?;el>qSE(Dw@u^i|mo7X|7Q2LQAjhYcz%FyQ26{QXK+!+3 zi{YMF61xW?5@=_bKcu7oYyRc%f6ez}*BE-Bi_!Rt;+GNqsIfDUj~bsB9_SPK`&*4U zI4#@W)cdgdmb0%r^iNCP`+8q@v|;y+ejxSJlGmsAh1nA9lKNk{Dxa3TI4SHF6&`3Z zlDYbUR8LFZlbT=J8!iX>@1otFmiIr#xTO2w@KgOjs;4EdTlc}?R_umI=m(NcOL1ik z>ppsJMzUBvkZ@Y6dm2fjzd#kFuzOb{kiu!{Jn|W)%wHh+r_fc()B*{orM_~mW7m!G z8>k)03tEAM)6!oHlJ))r{hlm#N3{Y8r=`Eou*)#je<1ns;RKIs1QJe5e}6=B98*l7 zSCD+D5lA>K{dLI)R$QP-q_Mk2okAetw3IiC+t{VJ&wrp??K>3$38$sJUAg}Z{sS#U zl3|`gAmOwWS5Fp6L-BzOXOMhROd#R3^w*1|7o!pAMPzII2U0sN|F2_NrV}X6MI_h# zzEVIqE$!7Xgyef-I)Mx=$PQv6yBJ52{aN$H0_TynM>fzVWZ&t&nqn!kF&ZM7r-^Z7 zi*y4Sx{(b~6S+Lo8AP@hqaA1lDP(7)h4`it23f{(e&3T^J8OPgY9&+`%xzQgq>xr{L1LD9cX%5YSigyU3DThQDIM2xMqsoP3Pa$sFb9TwQtpFDq7H!U|+~j#2V6!7)}+ zuJDX~6`zr>5uU|_8OTu274mnD_gLcdGg}!?)4_G}cbWN^umc%tIY(iBWgqR#BbMif zJ08MBA&}u-I`LzKGj#9Y?Af-0sknzyh;ocejs@>_%~tM%flGm8G_hi&f(gB zS%lGFaL+VX(2pzM3r|Uv1L;Rv&MAV{%Q9k^s0WhQ$PUs3VU*6`pXnN0?0z~)z3Rx`G8!u292#CG8`Cs!c=gWUwFaJ%vR4aC=cFyHm<)y!ae82BD z$o+S^rSo&ViqG8rGYl&KIUV})(_TpGS-oe*%>NTEnEY2;nETJ&>G2gTe~DWM4fMkq+2 literal 0 HcmV?d00001 diff --git a/coalMiningApp/matisse/src/main/res/drawable-xxxhdpi/ic_check_white_18dp.png b/coalMiningApp/matisse/src/main/res/drawable-xxxhdpi/ic_check_white_18dp.png new file mode 100644 index 0000000000000000000000000000000000000000..2c2ad771f72c8beaa5adbff66526893d8767990d GIT binary patch literal 276 zcmV+v0qg#WP)i*jo}i373|mq*}I4NcaPr1vPBqUj4{So^{}zU z+2V@M76*V4(wk$0gq_FHCw*~rLF6PjJvrp8;xy!tvzjxILyidcxS;vzge%E8;0~bA zCza(K@t8(4No6@FJiXx|O)AO}!Fe{GAi-fQe6!HylPYi`B&W#9B~|3)kkD4;1WDtE zgcdi2M1XboCryi6C~+>FcwG}oCT5=CqmNX1W4MP8OZ|2BU#~0BugB|7-NjF ae|iA|xq+-YC!0F}0000 literal 0 HcmV?d00001 diff --git a/coalMiningApp/matisse/src/main/res/drawable-xxxhdpi/ic_empty_dracula.png b/coalMiningApp/matisse/src/main/res/drawable-xxxhdpi/ic_empty_dracula.png new file mode 100644 index 0000000000000000000000000000000000000000..4fc34d81016bd1734489a090bdd0f2a9fa74f1fa GIT binary patch literal 17923 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 literal 0 HcmV?d00001 diff --git a/coalMiningApp/matisse/src/main/res/drawable-xxxhdpi/ic_empty_zhihu.png b/coalMiningApp/matisse/src/main/res/drawable-xxxhdpi/ic_empty_zhihu.png new file mode 100644 index 0000000000000000000000000000000000000000..9b3c3f1884955d12a1f2becb1b39bab5fd9351d1 GIT binary patch literal 17553 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 literal 0 HcmV?d00001 diff --git a/coalMiningApp/matisse/src/main/res/drawable-xxxhdpi/ic_photo_camera_white_24dp.png b/coalMiningApp/matisse/src/main/res/drawable-xxxhdpi/ic_photo_camera_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..777658e95515ca47c9852d00621e2e6d45abc5c7 GIT binary patch literal 894 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 literal 0 HcmV?d00001 diff --git a/coalMiningApp/matisse/src/main/res/layout/activity_matisse.xml b/coalMiningApp/matisse/src/main/res/layout/activity_matisse.xml new file mode 100644 index 0000000..6bf0c9b --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/layout/activity_matisse.xml @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/coalMiningApp/matisse/src/main/res/layout/activity_media_preview.xml b/coalMiningApp/matisse/src/main/res/layout/activity_media_preview.xml new file mode 100644 index 0000000..e9fc349 --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/layout/activity_media_preview.xml @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/coalMiningApp/matisse/src/main/res/layout/album_list_item.xml b/coalMiningApp/matisse/src/main/res/layout/album_list_item.xml new file mode 100644 index 0000000..1fc8d2f --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/layout/album_list_item.xml @@ -0,0 +1,57 @@ + + + + + + + + + + \ No newline at end of file diff --git a/coalMiningApp/matisse/src/main/res/layout/fragment_media_selection.xml b/coalMiningApp/matisse/src/main/res/layout/fragment_media_selection.xml new file mode 100644 index 0000000..79393ee --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/layout/fragment_media_selection.xml @@ -0,0 +1,31 @@ + + + + + + + diff --git a/coalMiningApp/matisse/src/main/res/layout/fragment_preview_item.xml b/coalMiningApp/matisse/src/main/res/layout/fragment_preview_item.xml new file mode 100644 index 0000000..2cfc58d --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/layout/fragment_preview_item.xml @@ -0,0 +1,32 @@ + + + + + + + + diff --git a/coalMiningApp/matisse/src/main/res/layout/media_grid_content.xml b/coalMiningApp/matisse/src/main/res/layout/media_grid_content.xml new file mode 100644 index 0000000..711557c --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/layout/media_grid_content.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/coalMiningApp/matisse/src/main/res/layout/media_grid_item.xml b/coalMiningApp/matisse/src/main/res/layout/media_grid_item.xml new file mode 100644 index 0000000..392e38b --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/layout/media_grid_item.xml @@ -0,0 +1,21 @@ + + + \ No newline at end of file diff --git a/coalMiningApp/matisse/src/main/res/layout/photo_capture_item.xml b/coalMiningApp/matisse/src/main/res/layout/photo_capture_item.xml new file mode 100644 index 0000000..9c30942 --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/layout/photo_capture_item.xml @@ -0,0 +1,36 @@ + + + + + + + \ No newline at end of file diff --git a/coalMiningApp/matisse/src/main/res/values-ar/strings.xml b/coalMiningApp/matisse/src/main/res/values-ar/strings.xml new file mode 100644 index 0000000..784cc64 --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/values-ar/strings.xml @@ -0,0 +1,20 @@ + + + جميع وسائل الإعلام + + معاينة + تطبيق + تطبيق (%1$d) + رجوع + كاميرا + لا وسائل الإعلام حتى الآن + تم + + لقد وصلت إلى الحد الأقصى للاختيار + يمكنك تحديد ما يصل إلى %1$d من ملفات الوسائط فقط + تحت الجودة + فوق الجودة + نوع ملف غير مدعوم + لا يمكن تحديد الصور ومقاطع الفيديو في نفس الوقت + لم يتم العثور على التطبيق دعم معاينة الفيديو + diff --git a/coalMiningApp/matisse/src/main/res/values-ca/strings.xml b/coalMiningApp/matisse/src/main/res/values-ca/strings.xml new file mode 100644 index 0000000..0611d09 --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/values-ca/strings.xml @@ -0,0 +1,35 @@ + + + + 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/coalMiningApp/matisse/src/main/res/values-de/strings.xml b/coalMiningApp/matisse/src/main/res/values-de/strings.xml new file mode 100644 index 0000000..b92112b --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/values-de/strings.xml @@ -0,0 +1,32 @@ + + + + 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/coalMiningApp/matisse/src/main/res/values-es/strings.xml b/coalMiningApp/matisse/src/main/res/values-es/strings.xml new file mode 100644 index 0000000..5339a3b --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/values-es/strings.xml @@ -0,0 +1,35 @@ + + + + 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/coalMiningApp/matisse/src/main/res/values-it/strings.xml b/coalMiningApp/matisse/src/main/res/values-it/strings.xml new file mode 100644 index 0000000..fbf5082 --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/values-it/strings.xml @@ -0,0 +1,35 @@ + + + + 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/coalMiningApp/matisse/src/main/res/values-ko/strings.xml b/coalMiningApp/matisse/src/main/res/values-ko/strings.xml new file mode 100644 index 0000000..7612d66 --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/values-ko/strings.xml @@ -0,0 +1,18 @@ + + + 전체보기 + 미리보기 + 카메라 + 비디오 미리보기를 지원하는 앱을 찾을 수 없습니다. + 이미지와 비디오는 동시에 선택 할 수 없습니다. + 적용 + 적용(%1$d) + 뒤로 + 미디어 파일이 없습니다. + 확인 + 더이상 선택할 수 없습니다. + 최대 %1$d까지 선택 가능합니다. + 화질이 너무 낮습니다. + 화질이 너무 높습니다. + 지원되지 않는 파일 유형입니다. + \ No newline at end of file diff --git a/coalMiningApp/matisse/src/main/res/values-pl/strings.xml b/coalMiningApp/matisse/src/main/res/values-pl/strings.xml new file mode 100644 index 0000000..739aead --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/values-pl/strings.xml @@ -0,0 +1,38 @@ + + + + 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/coalMiningApp/matisse/src/main/res/values-pt-rBR/strings.xml b/coalMiningApp/matisse/src/main/res/values-pt-rBR/strings.xml new file mode 100644 index 0000000..75447a0 --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/values-pt-rBR/strings.xml @@ -0,0 +1,35 @@ + + + + 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/coalMiningApp/matisse/src/main/res/values-ru/strings.xml b/coalMiningApp/matisse/src/main/res/values-ru/strings.xml new file mode 100644 index 0000000..2be64f2 --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/values-ru/strings.xml @@ -0,0 +1,43 @@ + + + + Все + + Предпросмотр + Применить + Применить(%1$d) + Назад + Камера + Пусто + OK + + Вы выбрали максимальное количество файлов + + Можно выбрать не более %1$d файла + Можно выбрать не более %1$d файлов + Можно выбрать не более %1$d файлов + Можно выбрать не более %1$d файлов + + Слишком низкое качество + Слишком высокое качество + Неподдерживаемый тип файла + Невозможно выбрать изображения и видео одновременно + Приложение для предпросмотра видео не найдено + Оригинал + Применить(%1$d) + Применить + diff --git a/coalMiningApp/matisse/src/main/res/values-tr-rTR/strings.xml b/coalMiningApp/matisse/src/main/res/values-tr-rTR/strings.xml new file mode 100644 index 0000000..671e3fb --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/values-tr-rTR/strings.xml @@ -0,0 +1,35 @@ + + + + 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/coalMiningApp/matisse/src/main/res/values-uk/strings.xml b/coalMiningApp/matisse/src/main/res/values-uk/strings.xml new file mode 100644 index 0000000..97cea27 --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/values-uk/strings.xml @@ -0,0 +1,40 @@ + + + + Всі + + Перегляд + Застосувати + Застосувати(%1$d) + Назад + Камера + Пусто + OK + + Вы обрали максимальну кількість файлів + + Можливо обрати не більше %1$d файла + Можливо обрати не більше %1$d файлів + Можливо обрати не більше %1$d файлів + Можливо обрати не більше %1$d файлів + + Занадто низька якість + Занадто висока якість + Непідтримуваний тип файла + Неможливо обрати зображення і відео одночасно + Застосунок для перегляду відео не знайдений + diff --git a/coalMiningApp/matisse/src/main/res/values-vi/strings.xml b/coalMiningApp/matisse/src/main/res/values-vi/strings.xml new file mode 100644 index 0000000..eb04ab7 --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/values-vi/strings.xml @@ -0,0 +1,23 @@ + + + Không thể chọn hình ảnh lớn hơn %1$d MB + Tất cả + Áp dụng(%1$d) + Áp dụng + Về + Đồng ý + Bản gốc + Xem trước + Đồng ý(%1$d) + Đồng ý + Chưa có dữ liệu + Không hỗ trợ loại tệp này + Không tìm thấy ứng dụng nào hỗ trợ xem trước video + Bạn chỉ có thể chọn tối đa %1$d tệp + Bạn đã đạt đến mức tối đa có thể lựa chọn + %1$d hình ảnh trên %2$d MB. Bản gốc sẽ được bỏ chọn + Chất lượng quá cao + Không thể chọn hình ảnh và video cùng một lúc + Chất lượng thấp + Camera + \ No newline at end of file diff --git a/coalMiningApp/matisse/src/main/res/values-zh-rTW/strings.xml b/coalMiningApp/matisse/src/main/res/values-zh-rTW/strings.xml new file mode 100644 index 0000000..fc77408 --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/values-zh-rTW/strings.xml @@ -0,0 +1,38 @@ + + + + 全部 + + 預覽 + 使用 + 使用(%1$d) + 返回 + 拍一張 + 還沒有圖片或影片 + 我知道了 + + 您已經達到最大選擇數量 + 最多只能選擇 %1$d 個文件 + 圖片質量太低 + 圖片質量太高 + 不支援的文件類型 + 不能同時選擇圖片和影片 + 沒有支持影片預覽的應用程式 + 原圖 + 确定 + 确定(%1$d) + \ No newline at end of file diff --git a/coalMiningApp/matisse/src/main/res/values-zh/strings.xml b/coalMiningApp/matisse/src/main/res/values-zh/strings.xml new file mode 100644 index 0000000..bdc4d47 --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/values-zh/strings.xml @@ -0,0 +1,47 @@ + + + + 全部 + + 预览 + 使用 + 使用(%1$d) + 返回 + 拍一张 + 还没有图片或视频 + 我知道了 + + 您已经达到最大选择数量 + 最多只能选择 %1$d 个文件 + 图片质量太低 + 图片质量太高 + 不支持的文件类型 + 不能同时选择图片和视频 + 没有支持视频预览的应用 + "该照片大于 %1$d M,无法上传将取消勾选原图" + "有 %1$d 张照片大于 %2$d M\n无法上传,将取消勾选原图" + 原图 + 确定 + 确定(%1$d) + + + 不能选择多于 %d 个文件 + 不能选择多于 %d 个文件 + 不能选择多于 %d 个文件 + 不能选择多于 %d 个文件 + + \ No newline at end of file diff --git a/coalMiningApp/matisse/src/main/res/values/attrs.xml b/coalMiningApp/matisse/src/main/res/values/attrs.xml new file mode 100644 index 0000000..852a3e3 --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/values/attrs.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/coalMiningApp/matisse/src/main/res/values/colors.xml b/coalMiningApp/matisse/src/main/res/values/colors.xml new file mode 100644 index 0000000..24ec1f9 --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/values/colors.xml @@ -0,0 +1,22 @@ + + + + + #CC000000 + #61FFFFFF + + \ No newline at end of file diff --git a/coalMiningApp/matisse/src/main/res/values/colors_dracula.xml b/coalMiningApp/matisse/src/main/res/values/colors_dracula.xml new file mode 100644 index 0000000..e8bb64f --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/values/colors_dracula.xml @@ -0,0 +1,43 @@ + + + + #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/coalMiningApp/matisse/src/main/res/values/colors_zhihu.xml b/coalMiningApp/matisse/src/main/res/values/colors_zhihu.xml new file mode 100644 index 0000000..4cf43fa --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/values/colors_zhihu.xml @@ -0,0 +1,45 @@ + + + + #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/coalMiningApp/matisse/src/main/res/values/dimens.xml b/coalMiningApp/matisse/src/main/res/values/dimens.xml new file mode 100644 index 0000000..f32d77a --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/values/dimens.xml @@ -0,0 +1,22 @@ + + + + 48dp + 4dp + + 72dp + \ No newline at end of file diff --git a/coalMiningApp/matisse/src/main/res/values/strings.xml b/coalMiningApp/matisse/src/main/res/values/strings.xml new file mode 100644 index 0000000..d5c0a4c --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/values/strings.xml @@ -0,0 +1,49 @@ + + + + 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) + + + No more than %d files can be selected + No more than %d files can be selected + No more than %d files can be selected + No more than %d files can be selected + + diff --git a/coalMiningApp/matisse/src/main/res/values/styles.xml b/coalMiningApp/matisse/src/main/res/values/styles.xml new file mode 100644 index 0000000..c1f9441 --- /dev/null +++ b/coalMiningApp/matisse/src/main/res/values/styles.xml @@ -0,0 +1,86 @@ + + + + + //====================================== Theme Zhihu =========================================== + + + + + + + + //===================================== Theme Dracula ========================================== + + + + + + + + \ No newline at end of file