From 46fc6b6b82264017ee00a026a034fce6f89085f2 Mon Sep 17 00:00:00 2001 From: HuXiaobai <1203747102@qq.com> Date: Tue, 20 Nov 2018 13:59:37 +0800 Subject: [PATCH 1/3] =?UTF-8?q?2.1.0=E5=BC=80=E5=8F=91=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../imagecompress/activity/MainActivity.java | 2 - .../imagecompress/base/CameraActivity.java | 32 +- .../src/main/java/utils/CompressPicker.java | 90 ++-- config.gradle | 24 +- matisse/build.gradle | 103 ---- matisse/gradle.properties | 0 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 | 153 ------ .../com/zhihu/matisse/SelectionCreator.java | 367 -------------- .../com/zhihu/matisse/engine/ImageEngine.java | 82 ---- .../matisse/engine/impl/GlideEngine.java | 92 ---- .../matisse/engine/impl/PicassoEngine.java | 61 --- .../java/com/zhihu/matisse/filter/Filter.java | 69 --- .../zhihu/matisse/internal/entity/Album.java | 120 ----- .../internal/entity/CaptureStrategy.java | 33 -- .../internal/entity/IncapableCause.java | 83 ---- .../zhihu/matisse/internal/entity/Item.java | 159 ------ .../internal/entity/SelectionSpec.java | 114 ----- .../matisse/internal/loader/AlbumLoader.java | 119 ----- .../internal/loader/AlbumMediaLoader.java | 154 ------ .../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 | 292 ----------- .../internal/ui/adapter/AlbumsAdapter.java | 74 --- .../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 - .../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 | 428 ---------------- .../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 123 -> 0 bytes .../res/drawable-hdpi/ic_check_white_18dp.png | Bin 152 -> 0 bytes .../res/drawable-hdpi/ic_empty_dracula.png | Bin 5911 -> 0 bytes .../main/res/drawable-hdpi/ic_empty_zhihu.png | Bin 5785 -> 0 bytes matisse/src/main/res/drawable-hdpi/ic_gif.png | Bin 929 -> 0 bytes .../ic_play_circle_outline_white_48dp.png | Bin 1023 -> 0 bytes .../drawable-hdpi/ic_preview_radio_off.webp | Bin 290 -> 0 bytes .../drawable-hdpi/ic_preview_radio_on.webp | Bin 338 -> 0 bytes .../ic_arrow_drop_down_white_24dp.png | Bin 95 -> 0 bytes .../res/drawable-mdpi/ic_check_white_18dp.png | Bin 146 -> 0 bytes .../res/drawable-mdpi/ic_empty_dracula.png | Bin 4018 -> 0 bytes .../main/res/drawable-mdpi/ic_empty_zhihu.png | Bin 3843 -> 0 bytes matisse/src/main/res/drawable-mdpi/ic_gif.png | Bin 638 -> 0 bytes .../ic_play_circle_outline_white_48dp.png | Bin 699 -> 0 bytes .../drawable-mdpi/ic_preview_radio_off.webp | Bin 410 -> 0 bytes .../drawable-mdpi/ic_preview_radio_on.webp | Bin 486 -> 0 bytes .../ic_arrow_drop_down_white_24dp.png | Bin 120 -> 0 bytes .../drawable-xhdpi/ic_check_white_18dp.png | Bin 181 -> 0 bytes .../res/drawable-xhdpi/ic_empty_dracula.png | Bin 8159 -> 0 bytes .../res/drawable-xhdpi/ic_empty_zhihu.png | Bin 7977 -> 0 bytes .../src/main/res/drawable-xhdpi/ic_gif.png | Bin 993 -> 0 bytes .../ic_play_circle_outline_white_48dp.png | Bin 1379 -> 0 bytes .../drawable-xhdpi/ic_preview_radio_off.webp | Bin 544 -> 0 bytes .../drawable-xhdpi/ic_preview_radio_on.webp | Bin 644 -> 0 bytes .../ic_arrow_drop_down_white_24dp.png | Bin 152 -> 0 bytes .../drawable-xxhdpi/ic_check_white_18dp.png | Bin 236 -> 0 bytes .../res/drawable-xxhdpi/ic_empty_dracula.png | Bin 13087 -> 0 bytes .../res/drawable-xxhdpi/ic_empty_zhihu.png | Bin 12785 -> 0 bytes .../src/main/res/drawable-xxhdpi/ic_gif.png | Bin 1380 -> 0 bytes .../ic_play_circle_outline_white_48dp.png | Bin 2145 -> 0 bytes .../ic_arrow_drop_down_white_24dp.png | Bin 185 -> 0 bytes .../drawable-xxxhdpi/ic_check_white_18dp.png | Bin 276 -> 0 bytes .../res/drawable-xxxhdpi/ic_empty_dracula.png | Bin 17923 -> 0 bytes .../res/drawable-xxxhdpi/ic_empty_zhihu.png | Bin 17553 -> 0 bytes .../src/main/res/drawable-xxxhdpi/ic_gif.png | Bin 1712 -> 0 bytes .../ic_photo_camera_white_24dp.png | Bin 894 -> 0 bytes .../ic_play_circle_outline_white_48dp.png | Bin 2836 -> 0 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 -- matisse/src/main/res/values-ar/strings.xml | 20 - matisse/src/main/res/values-ca/strings.xml | 35 -- matisse/src/main/res/values-de/strings.xml | 32 -- matisse/src/main/res/values-es/strings.xml | 35 -- matisse/src/main/res/values-it/strings.xml | 35 -- matisse/src/main/res/values-ko/strings.xml | 18 - matisse/src/main/res/values-pl/strings.xml | 38 -- .../src/main/res/values-pt-rBR/strings.xml | 35 -- matisse/src/main/res/values-ru/strings.xml | 43 -- .../src/main/res/values-tr-rTR/strings.xml | 35 -- matisse/src/main/res/values-uk/strings.xml | 40 -- .../src/main/res/values-zh-rTW/strings.xml | 38 -- matisse/src/main/res/values-zh/strings.xml | 40 -- matisse/src/main/res/values/attrs.xml | 36 -- matisse/src/main/res/values/colors.xml | 22 - .../src/main/res/values/colors_dracula.xml | 43 -- matisse/src/main/res/values/colors_zhihu.xml | 45 -- matisse/src/main/res/values/dimens.xml | 22 - matisse/src/main/res/values/strings.xml | 42 -- matisse/src/main/res/values/styles.xml | 86 ---- media/.gitignore | 1 + media/build.gradle | 53 ++ {app => media}/libs/systembartint-1.0.4.jar | Bin media/proguard-rules.pro | 21 + media/src/main/AndroidManifest.xml | 25 + .../java/com/example/media/MediaSelector.java | 131 +++++ .../media/OnRecyclerItemClickListener.java | 8 + .../example/media/activity/BaseActivity.java | 95 ++++ .../example/media/activity/MediaActivity.java | 462 ++++++++++++++++++ .../media/activity/PreviewActivity.java | 345 +++++++++++++ .../media/adapter/MediaCheckAdapter.java | 98 ++++ .../media/adapter/MediaFileAdapter.java | 148 ++++++ .../media/adapter/MediaFolderAdapter.java | 103 ++++ .../example/media/adapter/PreviewAdapter.java | 158 ++++++ .../example/media/bean/MediaSelectorFile.java | 114 +++++ .../media/bean/MediaSelectorFolder.java | 75 +++ .../example/media/permission/IntentUtils.java | 46 ++ .../media/permission/PermissionActivity.java | 189 +++++++ .../media/permission/PermissionFragment.java | 185 +++++++ .../permission/imp/OnPermissionsResult.java | 23 + .../example/media/provider/MediaProvider.java | 17 + .../media/resolver/ActivityManger.java | 60 +++ .../com/example/media/resolver/Contast.java | 21 + .../media/resolver/ILoadMediaResult.java | 9 + .../example/media/resolver/MediaHelper.java | 148 ++++++ .../com/example/media/utils/DateUtils.java | 26 + .../com/example/media/utils/FileUtils.java | 140 ++++++ .../com/example/media/utils/GlideUtils.java | 40 ++ .../com/example/media/utils/ScreenUtils.java | 115 +++++ .../example/media/weight/DialogHelper.java | 34 ++ .../example/media/weight/FolderWindow.java | 152 ++++++ .../example/media/weight/MediaScanner.java | 49 ++ .../media/weight/PreviewViewPager.java | 43 ++ .../java/com/example/media/weight/Toasts.java | 54 ++ media/src/main/res/anim/anim_dialog_in.xml | 7 + media/src/main/res/anim/anim_dialog_out.xml | 5 + .../main/res/drawable/selector_item_image.xml | 7 + .../drawable/selector_item_video_status.xml | 7 + .../main/res/drawable/shape_media_check.xml | 6 + .../main/res/drawable/shape_media_uncheck.xml | 6 + media/src/main/res/layout/activity_media.xml | 49 ++ .../src/main/res/layout/activity_preview.xml | 60 +++ .../res/layout/item_camera_media_view.xml | 14 + .../main/res/layout/item_check_media_view.xml | 22 + .../main/res/layout/item_media_file_view.xml | 54 ++ .../src/main/res/layout/item_media_folder.xml | 69 +++ .../main/res/layout/item_video_play_view.xml | 21 + .../src/main/res/layout/popup_media_view.xml | 19 + .../mipmap-xhdpi/icon_image_background.png | Bin 0 -> 763 bytes .../main/res/mipmap-xhdpi/icon_image_type.png | Bin 0 -> 191 bytes .../res/mipmap-xhdpi/icon_video_pause.png | Bin 0 -> 2714 bytes .../res/mipmap-xhdpi/icon_video_start.png | Bin 0 -> 3253 bytes .../main/res/mipmap-xxhdpi/icon_camera.png | Bin 0 -> 2754 bytes .../res/mipmap-xxhdpi/icon_folder_check.png | Bin 0 -> 1812 bytes .../res/mipmap-xxhdpi/icon_folder_uncheck.png | Bin 0 -> 1576 bytes .../res/mipmap-xxhdpi/icon_image_back.png | Bin 0 -> 313 bytes .../res/mipmap-xxhdpi/icon_image_checked.png | Bin 0 -> 1108 bytes .../mipmap-xxhdpi/icon_image_unchecked.png | Bin 0 -> 1205 bytes .../res/mipmap-xxhdpi/icon_preview_check.png | Bin 0 -> 671 bytes .../mipmap-xxhdpi/icon_preview_uncheck.png | Bin 0 -> 473 bytes .../res/mipmap-xxhdpi/icon_type_video.png | Bin 0 -> 463 bytes media/src/main/res/values/colors.xml | 10 + media/src/main/res/values/strings.xml | 25 + media/src/main/res/values/styles.xml | 14 + media/src/main/res/xml/provider_path.xml | 6 + settings.gradle | 2 +- 190 files changed, 3676 insertions(+), 7100 deletions(-) delete mode 100644 matisse/build.gradle delete mode 100644 matisse/gradle.properties delete mode 100644 matisse/proguard-rules.pro delete mode 100644 matisse/src/main/AndroidManifest.xml delete mode 100644 matisse/src/main/java/com/zhihu/matisse/Matisse.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/MimeType.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/SelectionCreator.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/engine/ImageEngine.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/engine/impl/GlideEngine.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/engine/impl/PicassoEngine.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/filter/Filter.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/entity/Album.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/entity/CaptureStrategy.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/entity/IncapableCause.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/entity/Item.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/entity/SelectionSpec.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/loader/AlbumLoader.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/loader/AlbumMediaLoader.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/model/AlbumCollection.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/model/AlbumMediaCollection.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/model/SelectedItemCollection.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/ui/AlbumPreviewActivity.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/ui/BasePreviewActivity.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/ui/MediaSelectionFragment.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/ui/PreviewItemFragment.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/ui/SelectedPreviewActivity.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/AlbumMediaAdapter.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/AlbumsAdapter.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/PreviewPagerAdapter.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/RecyclerViewCursorAdapter.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/AlbumsSpinner.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/CheckRadioView.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/CheckView.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/IncapableDialog.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/MediaGrid.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/MediaGridInset.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/PreviewViewPager.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/RoundedRectangleImageView.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/SquareFrameLayout.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/utils/ExifInterfaceCompat.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/utils/MediaStoreCompat.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/utils/PathUtils.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/utils/PhotoMetadataUtils.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/utils/Platform.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/internal/utils/UIUtils.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/listener/OnCheckedListener.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/listener/OnFragmentInteractionListener.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/listener/OnSelectedListener.java delete mode 100644 matisse/src/main/java/com/zhihu/matisse/ui/MatisseActivity.java delete mode 100644 matisse/src/main/res/color/dracula_bottom_toolbar_apply.xml delete mode 100644 matisse/src/main/res/color/dracula_bottom_toolbar_preview.xml delete mode 100644 matisse/src/main/res/color/dracula_preview_bottom_toolbar_apply.xml delete mode 100644 matisse/src/main/res/color/zhihu_bottom_toolbar_apply.xml delete mode 100644 matisse/src/main/res/color/zhihu_bottom_toolbar_preview.xml delete mode 100644 matisse/src/main/res/color/zhihu_preview_bottom_toolbar_apply.xml delete mode 100644 matisse/src/main/res/drawable-hdpi/ic_arrow_drop_down_white_24dp.png delete mode 100644 matisse/src/main/res/drawable-hdpi/ic_check_white_18dp.png delete mode 100644 matisse/src/main/res/drawable-hdpi/ic_empty_dracula.png delete mode 100644 matisse/src/main/res/drawable-hdpi/ic_empty_zhihu.png delete mode 100644 matisse/src/main/res/drawable-hdpi/ic_gif.png delete mode 100644 matisse/src/main/res/drawable-hdpi/ic_play_circle_outline_white_48dp.png delete mode 100644 matisse/src/main/res/drawable-hdpi/ic_preview_radio_off.webp delete mode 100644 matisse/src/main/res/drawable-hdpi/ic_preview_radio_on.webp delete mode 100644 matisse/src/main/res/drawable-mdpi/ic_arrow_drop_down_white_24dp.png delete mode 100644 matisse/src/main/res/drawable-mdpi/ic_check_white_18dp.png delete mode 100644 matisse/src/main/res/drawable-mdpi/ic_empty_dracula.png delete mode 100644 matisse/src/main/res/drawable-mdpi/ic_empty_zhihu.png delete mode 100644 matisse/src/main/res/drawable-mdpi/ic_gif.png delete mode 100644 matisse/src/main/res/drawable-mdpi/ic_play_circle_outline_white_48dp.png delete mode 100644 matisse/src/main/res/drawable-mdpi/ic_preview_radio_off.webp delete mode 100644 matisse/src/main/res/drawable-mdpi/ic_preview_radio_on.webp delete mode 100644 matisse/src/main/res/drawable-xhdpi/ic_arrow_drop_down_white_24dp.png delete mode 100644 matisse/src/main/res/drawable-xhdpi/ic_check_white_18dp.png delete mode 100644 matisse/src/main/res/drawable-xhdpi/ic_empty_dracula.png delete mode 100644 matisse/src/main/res/drawable-xhdpi/ic_empty_zhihu.png delete mode 100644 matisse/src/main/res/drawable-xhdpi/ic_gif.png delete mode 100644 matisse/src/main/res/drawable-xhdpi/ic_play_circle_outline_white_48dp.png delete mode 100644 matisse/src/main/res/drawable-xhdpi/ic_preview_radio_off.webp delete mode 100644 matisse/src/main/res/drawable-xhdpi/ic_preview_radio_on.webp delete mode 100644 matisse/src/main/res/drawable-xxhdpi/ic_arrow_drop_down_white_24dp.png delete mode 100644 matisse/src/main/res/drawable-xxhdpi/ic_check_white_18dp.png delete mode 100644 matisse/src/main/res/drawable-xxhdpi/ic_empty_dracula.png delete mode 100644 matisse/src/main/res/drawable-xxhdpi/ic_empty_zhihu.png delete mode 100644 matisse/src/main/res/drawable-xxhdpi/ic_gif.png delete mode 100644 matisse/src/main/res/drawable-xxhdpi/ic_play_circle_outline_white_48dp.png delete mode 100644 matisse/src/main/res/drawable-xxxhdpi/ic_arrow_drop_down_white_24dp.png delete mode 100644 matisse/src/main/res/drawable-xxxhdpi/ic_check_white_18dp.png delete mode 100644 matisse/src/main/res/drawable-xxxhdpi/ic_empty_dracula.png delete mode 100644 matisse/src/main/res/drawable-xxxhdpi/ic_empty_zhihu.png delete mode 100644 matisse/src/main/res/drawable-xxxhdpi/ic_gif.png delete mode 100644 matisse/src/main/res/drawable-xxxhdpi/ic_photo_camera_white_24dp.png delete mode 100644 matisse/src/main/res/drawable-xxxhdpi/ic_play_circle_outline_white_48dp.png delete mode 100644 matisse/src/main/res/layout/activity_matisse.xml delete mode 100644 matisse/src/main/res/layout/activity_media_preview.xml delete mode 100644 matisse/src/main/res/layout/album_list_item.xml delete mode 100644 matisse/src/main/res/layout/fragment_media_selection.xml delete mode 100644 matisse/src/main/res/layout/fragment_preview_item.xml delete mode 100644 matisse/src/main/res/layout/media_grid_content.xml delete mode 100644 matisse/src/main/res/layout/media_grid_item.xml delete mode 100644 matisse/src/main/res/layout/photo_capture_item.xml delete mode 100644 matisse/src/main/res/values-ar/strings.xml delete mode 100644 matisse/src/main/res/values-ca/strings.xml delete mode 100644 matisse/src/main/res/values-de/strings.xml delete mode 100644 matisse/src/main/res/values-es/strings.xml delete mode 100644 matisse/src/main/res/values-it/strings.xml delete mode 100644 matisse/src/main/res/values-ko/strings.xml delete mode 100644 matisse/src/main/res/values-pl/strings.xml delete mode 100644 matisse/src/main/res/values-pt-rBR/strings.xml delete mode 100644 matisse/src/main/res/values-ru/strings.xml delete mode 100644 matisse/src/main/res/values-tr-rTR/strings.xml delete mode 100644 matisse/src/main/res/values-uk/strings.xml delete mode 100644 matisse/src/main/res/values-zh-rTW/strings.xml delete mode 100644 matisse/src/main/res/values-zh/strings.xml delete mode 100644 matisse/src/main/res/values/attrs.xml delete mode 100644 matisse/src/main/res/values/colors.xml delete mode 100644 matisse/src/main/res/values/colors_dracula.xml delete mode 100644 matisse/src/main/res/values/colors_zhihu.xml delete mode 100644 matisse/src/main/res/values/dimens.xml delete mode 100644 matisse/src/main/res/values/strings.xml delete mode 100644 matisse/src/main/res/values/styles.xml create mode 100644 media/.gitignore create mode 100644 media/build.gradle rename {app => media}/libs/systembartint-1.0.4.jar (100%) create mode 100644 media/proguard-rules.pro create mode 100644 media/src/main/AndroidManifest.xml create mode 100644 media/src/main/java/com/example/media/MediaSelector.java create mode 100644 media/src/main/java/com/example/media/OnRecyclerItemClickListener.java create mode 100644 media/src/main/java/com/example/media/activity/BaseActivity.java create mode 100644 media/src/main/java/com/example/media/activity/MediaActivity.java create mode 100644 media/src/main/java/com/example/media/activity/PreviewActivity.java create mode 100644 media/src/main/java/com/example/media/adapter/MediaCheckAdapter.java create mode 100644 media/src/main/java/com/example/media/adapter/MediaFileAdapter.java create mode 100644 media/src/main/java/com/example/media/adapter/MediaFolderAdapter.java create mode 100644 media/src/main/java/com/example/media/adapter/PreviewAdapter.java create mode 100644 media/src/main/java/com/example/media/bean/MediaSelectorFile.java create mode 100644 media/src/main/java/com/example/media/bean/MediaSelectorFolder.java create mode 100644 media/src/main/java/com/example/media/permission/IntentUtils.java create mode 100644 media/src/main/java/com/example/media/permission/PermissionActivity.java create mode 100644 media/src/main/java/com/example/media/permission/PermissionFragment.java create mode 100644 media/src/main/java/com/example/media/permission/imp/OnPermissionsResult.java create mode 100644 media/src/main/java/com/example/media/provider/MediaProvider.java create mode 100644 media/src/main/java/com/example/media/resolver/ActivityManger.java create mode 100644 media/src/main/java/com/example/media/resolver/Contast.java create mode 100644 media/src/main/java/com/example/media/resolver/ILoadMediaResult.java create mode 100644 media/src/main/java/com/example/media/resolver/MediaHelper.java create mode 100644 media/src/main/java/com/example/media/utils/DateUtils.java create mode 100644 media/src/main/java/com/example/media/utils/FileUtils.java create mode 100644 media/src/main/java/com/example/media/utils/GlideUtils.java create mode 100644 media/src/main/java/com/example/media/utils/ScreenUtils.java create mode 100644 media/src/main/java/com/example/media/weight/DialogHelper.java create mode 100644 media/src/main/java/com/example/media/weight/FolderWindow.java create mode 100644 media/src/main/java/com/example/media/weight/MediaScanner.java create mode 100644 media/src/main/java/com/example/media/weight/PreviewViewPager.java create mode 100644 media/src/main/java/com/example/media/weight/Toasts.java create mode 100644 media/src/main/res/anim/anim_dialog_in.xml create mode 100644 media/src/main/res/anim/anim_dialog_out.xml create mode 100644 media/src/main/res/drawable/selector_item_image.xml create mode 100644 media/src/main/res/drawable/selector_item_video_status.xml create mode 100644 media/src/main/res/drawable/shape_media_check.xml create mode 100644 media/src/main/res/drawable/shape_media_uncheck.xml create mode 100644 media/src/main/res/layout/activity_media.xml create mode 100644 media/src/main/res/layout/activity_preview.xml create mode 100644 media/src/main/res/layout/item_camera_media_view.xml create mode 100644 media/src/main/res/layout/item_check_media_view.xml create mode 100644 media/src/main/res/layout/item_media_file_view.xml create mode 100644 media/src/main/res/layout/item_media_folder.xml create mode 100644 media/src/main/res/layout/item_video_play_view.xml create mode 100644 media/src/main/res/layout/popup_media_view.xml create mode 100644 media/src/main/res/mipmap-xhdpi/icon_image_background.png create mode 100644 media/src/main/res/mipmap-xhdpi/icon_image_type.png create mode 100644 media/src/main/res/mipmap-xhdpi/icon_video_pause.png create mode 100644 media/src/main/res/mipmap-xhdpi/icon_video_start.png create mode 100644 media/src/main/res/mipmap-xxhdpi/icon_camera.png create mode 100644 media/src/main/res/mipmap-xxhdpi/icon_folder_check.png create mode 100644 media/src/main/res/mipmap-xxhdpi/icon_folder_uncheck.png create mode 100644 media/src/main/res/mipmap-xxhdpi/icon_image_back.png create mode 100644 media/src/main/res/mipmap-xxhdpi/icon_image_checked.png create mode 100644 media/src/main/res/mipmap-xxhdpi/icon_image_unchecked.png create mode 100644 media/src/main/res/mipmap-xxhdpi/icon_preview_check.png create mode 100644 media/src/main/res/mipmap-xxhdpi/icon_preview_uncheck.png create mode 100644 media/src/main/res/mipmap-xxhdpi/icon_type_video.png create mode 100644 media/src/main/res/values/colors.xml create mode 100644 media/src/main/res/values/strings.xml create mode 100644 media/src/main/res/values/styles.xml create mode 100644 media/src/main/res/xml/provider_path.xml diff --git a/app/src/main/java/com/baixiaohu/imagecompress/activity/MainActivity.java b/app/src/main/java/com/baixiaohu/imagecompress/activity/MainActivity.java index 66c9b71..c1772fe 100644 --- a/app/src/main/java/com/baixiaohu/imagecompress/activity/MainActivity.java +++ b/app/src/main/java/com/baixiaohu/imagecompress/activity/MainActivity.java @@ -10,8 +10,6 @@ import com.baixiaohu.imagecompress.dialog.ExitDialog; import com.baixiaohu.imagecompress.permission.imp.OnPermissionsResult; import com.baixiaohu.imagecompress.toast.Toasts; -import com.bumptech.glide.Glide; -import com.squareup.haha.perflib.Main; import java.util.List; diff --git a/app/src/main/java/com/baixiaohu/imagecompress/base/CameraActivity.java b/app/src/main/java/com/baixiaohu/imagecompress/base/CameraActivity.java index e684364..c318817 100644 --- a/app/src/main/java/com/baixiaohu/imagecompress/base/CameraActivity.java +++ b/app/src/main/java/com/baixiaohu/imagecompress/base/CameraActivity.java @@ -11,9 +11,9 @@ import com.baixiaohu.imagecompress.dialog.PhotoDialog; import com.baixiaohu.imagecompress.permission.imp.OnPermissionsResult; import com.baixiaohu.imagecompress.toast.Toasts; -import com.zhihu.matisse.Matisse; -import com.zhihu.matisse.MimeType; -import com.zhihu.matisse.engine.impl.GlideEngine; +import com.example.media.MediaSelector; +import com.example.media.bean.MediaSelectorFile; +import com.example.media.resolver.Contast; import java.io.File; import java.io.IOException; @@ -121,14 +121,7 @@ public void onClickCancel(View view) { } protected void openZhiHuAlbum() { - Matisse.from(this) - .choose(MimeType.ofImage()) - .countable(true) - .maxSelectable(9) - .restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) - .thumbnailScale(0.85f) - .imageEngine(new GlideEngine()) - .forResult(REQUEST_CODE_CHOOSE); + MediaSelector.with(this).openMediaActivity(); } @Override @@ -163,16 +156,16 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { imageFileResult(bean); } - } else if (requestCode == REQUEST_CODE_CHOOSE) { - List pathData = Matisse.obtainPathResult(data); - if (pathData == null || pathData.size() == 0) + } + break; + case Contast.CODE_RESULT_MEDIA: + if (requestCode == Contast.CODE_REQUEST_MEDIA) { + List mediaData = MediaSelector.resultMediaFile(data); + if (mediaData == null || mediaData.size() == 0) return; List imageFileBeanList = new ArrayList<>(); - for (String path : pathData) { - if (path == null) { - return; - } - File file = new File(path); + for (MediaSelectorFile mediaSelectorFile : mediaData) { + File file = new File(mediaSelectorFile.filePath); if (FileUtils.isImageFile(file)) { ImageFileBean imageFileBean = new ImageFileBean(); imageFileBean.isImage = true; @@ -185,6 +178,7 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { imageFilesResult(imageFileBeanList); } break; + default: break; } diff --git a/compress/src/main/java/utils/CompressPicker.java b/compress/src/main/java/utils/CompressPicker.java index 3f753a3..8a794f9 100644 --- a/compress/src/main/java/utils/CompressPicker.java +++ b/compress/src/main/java/utils/CompressPicker.java @@ -1,10 +1,14 @@ package utils; +import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.ImageDecoder; import android.graphics.Matrix; +import android.graphics.drawable.AnimatedImageDrawable; import android.media.ExifInterface; +import android.os.Build; import android.support.annotation.NonNull; @@ -41,43 +45,65 @@ public class CompressPicker { * @param imageConfig bean * @return 返回Bitmap */ - public static Bitmap compressBitmap(ImageConfig imageConfig) { + public static Bitmap compressBitmap(final ImageConfig imageConfig) { Bitmap bitmap = null; if (null != imageConfig) { - CompressPicker.mImageConfig = imageConfig; - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inPreferredConfig = imageConfig.config; - options.inJustDecodeBounds = true; - BitmapFactory.decodeFile(imageConfig.imagePath, options); - options.inSampleSize = (int) ((options.outWidth * 1.0f) / (imageConfig.compressWidth * 1.0f) + (options.outHeight * 1.0f) / (imageConfig.compressHeight * 1.0f)) / 2; - options.inJustDecodeBounds = false; - options.inScaled = false; - options.inMutable = true; - bitmap = BitmapFactory.decodeFile(imageConfig.imagePath, options); - ExifInterface exif; - try { - exif = new ExifInterface(imageConfig.imagePath); - int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0); - Matrix matrix = new Matrix(); - switch (orientation) { - case ExifInterface.ORIENTATION_ROTATE_90: - matrix.postRotate(90); - break; - case ExifInterface.ORIENTATION_ROTATE_180: - matrix.postRotate(180); - break; - case ExifInterface.ORIENTATION_ROTATE_270: - matrix.postRotate(270); - break; - default: - break; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + ImageDecoder.Source source = ImageDecoder.createSource(new File(imageConfig.imagePath)); + try { + bitmap = ImageDecoder.decodeBitmap(source, new ImageDecoder.OnHeaderDecodedListener() { + @Override + public void onHeaderDecoded(ImageDecoder decoder, ImageDecoder.ImageInfo info, ImageDecoder.Source source) { + decoder.setTargetSize(imageConfig.compressWidth, imageConfig.compressHeight); + decoder.setTargetSampleSize(150*1024); + decoder.setMutableRequired(true); + decoder.setMemorySizePolicy(); + decoder.close(); + } + }); + } catch (IOException e) { + e.printStackTrace(); } - bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); - } catch (IOException e) { - e.printStackTrace(); - return bitmap; + } else { + CompressPicker.mImageConfig = imageConfig; + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inPreferredConfig = imageConfig.config; + options.inJustDecodeBounds = true; + BitmapFactory.decodeFile(imageConfig.imagePath, options); + options.inSampleSize = (int) ((options.outWidth * 1.0f) / (imageConfig.compressWidth * 1.0f) + (options.outHeight * 1.0f) / (imageConfig.compressHeight * 1.0f)) / 2; + options.inJustDecodeBounds = false; + options.inScaled = false; + options.inMutable = true; + bitmap = BitmapFactory.decodeFile(imageConfig.imagePath, options); + } + if (bitmap != null) { + ExifInterface exif; + try { + exif = new ExifInterface(imageConfig.imagePath); + int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0); + Matrix matrix = new Matrix(); + switch (orientation) { + case ExifInterface.ORIENTATION_ROTATE_90: + matrix.postRotate(90); + break; + case ExifInterface.ORIENTATION_ROTATE_180: + matrix.postRotate(180); + break; + case ExifInterface.ORIENTATION_ROTATE_270: + matrix.postRotate(270); + break; + default: + break; + } + bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); + } catch (IOException e) { + e.printStackTrace(); + return bitmap; + } } + + } return bitmap; } diff --git a/config.gradle b/config.gradle index b5d5681..0e94cdd 100644 --- a/config.gradle +++ b/config.gradle @@ -1,33 +1,36 @@ ext { android = [ - compileSdkVersion: 27, + compileSdkVersion: 28, minSdkVersion : 15, - targetSdkVersion : 27, + targetSdkVersion : 28, versionCode : 1, versionName : "1.0", - buildToolsVersion: "27.0.3" + buildToolsVersion: "28.0.0" ] dependVersion = [ - appcompat : "27.1.1", + appcompat : "28.0.0", constraint : "1.0.2", junit : "4.12", runner : "1.0.1", espresso : "3.0.1", glide : "4.8.0", - design : "27.1.1", + design : "28.0.0", PhotoView : "2.0.0", multidex : "1.0.3", leakcanaryAndroid : "1.6.1", leakcanaryAndroidNoOp : "1.6.1", leakcanarySupportFragment: "1.6.1", - supportV4 : "27.1.1", + supportV4 : "28.0.0", rxjava : "2.0.0", rxandroid : "2.0.0", rxlifecycleComponents : "2.1.0", - recyclerview : "27.0.0", + recyclerview : "28.0.0", imagezoom : "1.0.4", - picasso : "2.5.2" + picasso : "2.5.2", + projectview : "1.0.1", + eventbus : "3.1.1", + ucrop : "2.2.2" ] @@ -50,7 +53,10 @@ ext { rxlifecycleComponents : "com.trello.rxlifecycle2:rxlifecycle-components:${dependVersion.rxlifecycleComponents}", recyclerview : "com.android.support:recyclerview-v7:${dependVersion.recyclerview}", imagezoom : "it.sephiroth.android.library.imagezoom:library:${dependVersion.imagezoom}", - picasso : "com.squareup.picasso:picasso:${dependVersion.picasso}" + picasso : "com.squareup.picasso:picasso:${dependVersion.picasso}", + projectview : "com.github.Hu12037102:ProjectView:${dependVersion.projectview}", + eventbus : "org.greenrobot:eventbus:${dependVersion.eventbus}", + ucrop : "com.github.yalantis:ucrop:${dependVersion.ucrop}" // rxlifecycleComponents:"com.trello.rxlifecycle2:rxlifecycle-android:${dependVersion.rxlifecycleComponents}" //implementation 'com.trello.rxlifecycle2:rxlifecycle-android:2.2.2' diff --git a/matisse/build.gradle b/matisse/build.gradle deleted file mode 100644 index 487d8bb..0000000 --- a/matisse/build.gradle +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -apply plugin: 'com.android.library' -apply plugin: 'checkstyle' - -/*android { - compileSdkVersion 27 - buildToolsVersion '27.0.3' - - defaultConfig { - minSdkVersion 14 - targetSdkVersion 27 - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_7 - targetCompatibility JavaVersion.VERSION_1_7 - } - lintOptions { - abortOnError false - } -}*/ - - -android { - - defaultConfig { - def versions = rootProject.ext.android - compileSdkVersion versions.compileSdkVersion - minSdkVersion versions.minSdkVersion - targetSdkVersion versions.targetSdkVersion - versionCode versions.versionCode - versionName versions.versionName - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - buildToolsVersion versions.buildToolsVersion - } - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - } -} - - - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) - def versions = rootProject.ext.dependencies - implementation versions.appcompatV7 - implementation versions.supportV4 - //implementation "com.android.support:support-annotations:${supportLibVersion}" - implementation versions.recyclerview - implementation versions.imagezoom - - compileOnly versions.glide - compileOnly versions.picasso -} - - - - - - -// jcenter configuration for novoda's bintray-release -// $ ./gradlew clean build bintrayUpload -PbintrayUser=BINTRAY_USERNAME -PbintrayKey=BINTRAY_KEY -PdryRun=false - - -/* -task javadoc(type: Javadoc) { - options.encoding = "utf-8" -} - -checkstyle { - toolVersion = '7.6.1' -} - -tasks.withType(Javadoc) { - options.addStringOption('Xdoclint:none', '-quiet') - options.addStringOption('encoding', 'UTF-8') -} - -task checkstyle(type:Checkstyle) { - description 'Runs Checkstyle inspection against matisse sourcesets.' - group = 'Code Quality' - configFile rootProject.file('checkstyle.xml') - ignoreFailures = false - showViolations true - classpath = files() - source 'src/main/java' -}*/ diff --git a/matisse/gradle.properties b/matisse/gradle.properties deleted file mode 100644 index e69de29..0000000 diff --git a/matisse/proguard-rules.pro b/matisse/proguard-rules.pro deleted file mode 100644 index f1ffffd..0000000 --- a/matisse/proguard-rules.pro +++ /dev/null @@ -1,19 +0,0 @@ -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in /Library/android-sdk-macosx/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the ProGuard -# include property in project.properties. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# Add any project specific keep options here: - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - --dontwarn com.squareup.okhttp.** diff --git a/matisse/src/main/AndroidManifest.xml b/matisse/src/main/AndroidManifest.xml deleted file mode 100644 index 7057835..0000000 --- a/matisse/src/main/AndroidManifest.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/matisse/src/main/java/com/zhihu/matisse/Matisse.java b/matisse/src/main/java/com/zhihu/matisse/Matisse.java deleted file mode 100644 index 7476321..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/Matisse.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse; - -import android.app.Activity; -import android.content.Intent; -import android.net.Uri; -import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; - -import com.zhihu.matisse.ui.MatisseActivity; - -import java.lang.ref.WeakReference; -import java.util.List; -import java.util.Set; - -/** - * Entry for Matisse's media selection. - */ -public final class Matisse { - - private final WeakReference mContext; - private final WeakReference mFragment; - - private Matisse(Activity activity) { - this(activity, null); - } - - private Matisse(Fragment fragment) { - this(fragment.getActivity(), fragment); - } - - private Matisse(Activity activity, Fragment fragment) { - mContext = new WeakReference<>(activity); - mFragment = new WeakReference<>(fragment); - } - - /** - * Start Matisse from an Activity. - *

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

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

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

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

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

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

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

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

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

- * It's a redundant API with {@link Matisse#obtainResult(Intent)}, - * we only suggest you to use this API when you need to do something immediately. - * - * @param listener {@link OnSelectedListener} - * @return {@link SelectionCreator} for fluent API. - */ - @NonNull - public SelectionCreator setOnSelectedListener(@Nullable OnSelectedListener listener) { - mSelectionSpec.onSelectedListener = listener; - return this; - } - - /** - * Set listener for callback immediately when user check or uncheck original. - * - * @param listener {@link OnSelectedListener} - * @return {@link SelectionCreator} for fluent API. - */ - public SelectionCreator setOnCheckedListener(@Nullable OnCheckedListener listener) { - mSelectionSpec.onCheckedListener = listener; - return this; - } - - /** - * Start to select media and wait for result. - * - * @param requestCode Identity of the request Activity or Fragment. - */ - public void forResult(int requestCode) { - Activity activity = mMatisse.getActivity(); - if (activity == null) { - return; - } - - Intent intent = new Intent(activity, MatisseActivity.class); - - Fragment fragment = mMatisse.getFragment(); - if (fragment != null) { - fragment.startActivityForResult(intent, requestCode); - } else { - activity.startActivityForResult(intent, requestCode); - } - } - -} diff --git a/matisse/src/main/java/com/zhihu/matisse/engine/ImageEngine.java b/matisse/src/main/java/com/zhihu/matisse/engine/ImageEngine.java deleted file mode 100644 index 84e5c96..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/engine/ImageEngine.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.engine; - -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.widget.ImageView; - -/** - * Image loader interface. There are predefined {@link com.zhihu.matisse.engine.impl.GlideEngine} - * and {@link com.zhihu.matisse.engine.impl.PicassoEngine}. - */ -@SuppressWarnings("unused") -public interface ImageEngine { - - /** - * Load thumbnail of a static image resource. - * - * @param context Context - * @param resize Desired size of the origin image - * @param placeholder Placeholder drawable when image is not loaded yet - * @param imageView ImageView widget - * @param uri Uri of the loaded image - */ - void loadThumbnail(Context context, int resize, Drawable placeholder, ImageView imageView, Uri uri); - - /** - * Load thumbnail of a gif image resource. You don't have to load an animated gif when it's only - * a thumbnail tile. - * - * @param context Context - * @param resize Desired size of the origin image - * @param placeholder Placeholder drawable when image is not loaded yet - * @param imageView ImageView widget - * @param uri Uri of the loaded image - */ - void loadGifThumbnail(Context context, int resize, Drawable placeholder, ImageView imageView, Uri uri); - - /** - * Load a static image resource. - * - * @param context Context - * @param resizeX Desired x-size of the origin image - * @param resizeY Desired y-size of the origin image - * @param imageView ImageView widget - * @param uri Uri of the loaded image - */ - void loadImage(Context context, int resizeX, int resizeY, ImageView imageView, Uri uri); - - /** - * Load a gif image resource. - * - * @param context Context - * @param resizeX Desired x-size of the origin image - * @param resizeY Desired y-size of the origin image - * @param imageView ImageView widget - * @param uri Uri of the loaded image - */ - void loadGifImage(Context context, int resizeX, int resizeY, ImageView imageView, Uri uri); - - /** - * Whether this implementation supports animated gif. - * Just knowledge of it, convenient for users. - * - * @return true support animated gif, false do not support animated gif. - */ - boolean supportAnimatedGif(); -} diff --git a/matisse/src/main/java/com/zhihu/matisse/engine/impl/GlideEngine.java b/matisse/src/main/java/com/zhihu/matisse/engine/impl/GlideEngine.java deleted file mode 100644 index d1b2049..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/engine/impl/GlideEngine.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.engine.impl; - -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.widget.ImageView; - -import com.bumptech.glide.Glide; -import com.bumptech.glide.Priority; -import com.bumptech.glide.request.RequestOptions; -import com.zhihu.matisse.engine.ImageEngine; - -/** - * {@link ImageEngine} implementation using Glide. - */ - -public class GlideEngine implements ImageEngine { - - @Override - public void loadThumbnail(Context context, int resize, Drawable placeholder, ImageView imageView, Uri uri) { - /* Glide.with(context) - .load(uri) - .asBitmap() // some .jpeg files are actually gif - .placeholder(placeholder) - .override(resize, resize) - .centerCrop() - .into(imageView);*/ - RequestOptions requestOptions = new RequestOptions().centerCrop(); - Glide.with(context).asDrawable().load(uri).apply(requestOptions).into(imageView); - } - - @Override - public void loadGifThumbnail(Context context, int resize, Drawable placeholder, ImageView imageView, - Uri uri) { - - RequestOptions requestOptions = new RequestOptions().override(resize,resize).centerCrop().error(placeholder).placeholder(placeholder); - Glide.with(context).asDrawable().load(uri).apply(requestOptions).into(imageView); - /*Glide.with(context) - .load(uri) - .asBitmap() - .placeholder(placeholder) - .override(resize, resize) - .centerCrop() - .into(imageView);*/ - } - - @Override - public void loadImage(Context context, int resizeX, int resizeY, ImageView imageView, Uri uri) { - /* Glide.with(context) - .load(uri) - .override(resizeX, resizeY) - .priority(Priority.HIGH) - .fitCenter() - .into(imageView);*/ - RequestOptions requestOptions = new RequestOptions().override(resizeX,resizeY).fitCenter().priority(Priority.HIGH); - Glide.with(context).asDrawable().load(uri).apply(requestOptions).into(imageView); - } - - @Override - public void loadGifImage(Context context, int resizeX, int resizeY, ImageView imageView, Uri uri) { - /*Glide.with(context) - .load(uri) - .asGif() - .override(resizeX, resizeY) - .priority(Priority.HIGH) - .into(imageView);*/ - - RequestOptions requestOptions = new RequestOptions().override(resizeX,resizeY).priority(Priority.HIGH); - Glide.with(context).asGif().load(uri).apply(requestOptions).into(imageView); - } - - @Override - public boolean supportAnimatedGif() { - return true; - } - -} diff --git a/matisse/src/main/java/com/zhihu/matisse/engine/impl/PicassoEngine.java b/matisse/src/main/java/com/zhihu/matisse/engine/impl/PicassoEngine.java deleted file mode 100644 index 4ee33ea..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/engine/impl/PicassoEngine.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.engine.impl; - -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.widget.ImageView; - -import com.squareup.picasso.Picasso; -import com.zhihu.matisse.engine.ImageEngine; - -/** - * {@link ImageEngine} implementation using Picasso. - */ - -public class PicassoEngine implements ImageEngine { - - @Override - public void loadThumbnail(Context context, int resize, Drawable placeholder, ImageView imageView, Uri uri) { - Picasso.with(context).load(uri).placeholder(placeholder) - .resize(resize, resize) - .centerCrop() - .into(imageView); - } - - @Override - public void loadGifThumbnail(Context context, int resize, Drawable placeholder, ImageView imageView, - Uri uri) { - loadThumbnail(context, resize, placeholder, imageView, uri); - } - - @Override - public void loadImage(Context context, int resizeX, int resizeY, ImageView imageView, Uri uri) { - Picasso.with(context).load(uri).resize(resizeX, resizeY).priority(Picasso.Priority.HIGH) - .centerInside().into(imageView); - } - - @Override - public void loadGifImage(Context context, int resizeX, int resizeY, ImageView imageView, Uri uri) { - loadImage(context, resizeX, resizeY, imageView, uri); - } - - @Override - public boolean supportAnimatedGif() { - return false; - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/filter/Filter.java b/matisse/src/main/java/com/zhihu/matisse/filter/Filter.java deleted file mode 100644 index 0942364..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/filter/Filter.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.filter; - -import android.content.Context; - -import com.zhihu.matisse.MimeType; -import com.zhihu.matisse.SelectionCreator; -import com.zhihu.matisse.internal.entity.Item; -import com.zhihu.matisse.internal.entity.IncapableCause; - -import java.util.Set; - -/** - * Filter for choosing a {@link Item}. You can add multiple Filters through - * {@link SelectionCreator#addFilter(Filter)}. - */ -@SuppressWarnings("unused") -public abstract class Filter { - /** - * Convenient constant for a minimum value. - */ - public static final int MIN = 0; - /** - * Convenient constant for a maximum value. - */ - public static final int MAX = Integer.MAX_VALUE; - /** - * Convenient constant for 1024. - */ - public static final int K = 1024; - - /** - * Against what mime types this filter applies. - */ - protected abstract Set constraintTypes(); - - /** - * Invoked for filtering each item. - * - * @return null if selectable, {@link IncapableCause} if not selectable. - */ - public abstract IncapableCause filter(Context context, Item item); - - /** - * Whether an {@link Item} need filtering. - */ - protected boolean needFiltering(Context context, Item item) { - for (MimeType type : constraintTypes()) { - if (type.checkType(context.getContentResolver(), item.getContentUri())) { - return true; - } - } - return false; - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/entity/Album.java b/matisse/src/main/java/com/zhihu/matisse/internal/entity/Album.java deleted file mode 100644 index 9ebafb8..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/entity/Album.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2014 nohana, Inc. - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.entity; - -import android.content.Context; -import android.database.Cursor; -import android.os.Parcel; -import android.os.Parcelable; -import android.provider.MediaStore; -import android.support.annotation.Nullable; - -import com.zhihu.matisse.R; -import com.zhihu.matisse.internal.loader.AlbumLoader; - -public class Album implements Parcelable { - public static final Creator CREATOR = new Creator() { - @Nullable - @Override - public Album createFromParcel(Parcel source) { - return new Album(source); - } - - @Override - public Album[] newArray(int size) { - return new Album[size]; - } - }; - public static final String ALBUM_ID_ALL = String.valueOf(-1); - public static final String ALBUM_NAME_ALL = "All"; - - private final String mId; - private final String mCoverPath; - private final String mDisplayName; - private long mCount; - - Album(String id, String coverPath, String albumName, long count) { - mId = id; - mCoverPath = coverPath; - mDisplayName = albumName; - mCount = count; - } - - Album(Parcel source) { - mId = source.readString(); - mCoverPath = source.readString(); - mDisplayName = source.readString(); - mCount = source.readLong(); - } - - /** - * Constructs a new {@link Album} entity from the {@link Cursor}. - * This method is not responsible for managing cursor resource, such as close, iterate, and so on. - */ - public static Album valueOf(Cursor cursor) { - return new Album( - cursor.getString(cursor.getColumnIndex("bucket_id")), - cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DATA)), - cursor.getString(cursor.getColumnIndex("bucket_display_name")), - cursor.getLong(cursor.getColumnIndex(AlbumLoader.COLUMN_COUNT))); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mId); - dest.writeString(mCoverPath); - dest.writeString(mDisplayName); - dest.writeLong(mCount); - } - - public String getId() { - return mId; - } - - public String getCoverPath() { - return mCoverPath; - } - - public long getCount() { - return mCount; - } - - public void addCaptureCount() { - mCount++; - } - - public String getDisplayName(Context context) { - if (isAll()) { - return context.getString(R.string.album_name_all); - } - return mDisplayName; - } - - public boolean isAll() { - return ALBUM_ID_ALL.equals(mId); - } - - public boolean isEmpty() { - return mCount == 0; - } - -} \ No newline at end of file diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/entity/CaptureStrategy.java b/matisse/src/main/java/com/zhihu/matisse/internal/entity/CaptureStrategy.java deleted file mode 100644 index c4de7ca..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/entity/CaptureStrategy.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.entity; - -public class CaptureStrategy { - - public final boolean isPublic; - public final String authority; - public final String directory; - - public CaptureStrategy(boolean isPublic, String authority) { - this(isPublic, authority, null); - } - - public CaptureStrategy(boolean isPublic, String authority, String directory) { - this.isPublic = isPublic; - this.authority = authority; - this.directory = directory; - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/entity/IncapableCause.java b/matisse/src/main/java/com/zhihu/matisse/internal/entity/IncapableCause.java deleted file mode 100644 index 5c39206..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/entity/IncapableCause.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.entity; - -import android.content.Context; -import android.support.annotation.IntDef; -import android.support.v4.app.FragmentActivity; -import android.widget.Toast; - -import com.zhihu.matisse.internal.ui.widget.IncapableDialog; - -import java.lang.annotation.Retention; - -import static java.lang.annotation.RetentionPolicy.SOURCE; - -@SuppressWarnings("unused") -public class IncapableCause { - public static final int TOAST = 0x00; - public static final int DIALOG = 0x01; - public static final int NONE = 0x02; - - @Retention(SOURCE) - @IntDef({TOAST, DIALOG, NONE}) - public @interface Form { - } - - private int mForm = TOAST; - private String mTitle; - private String mMessage; - - public IncapableCause(String message) { - mMessage = message; - } - - public IncapableCause(String title, String message) { - mTitle = title; - mMessage = message; - } - - public IncapableCause(@Form int form, String message) { - mForm = form; - mMessage = message; - } - - public IncapableCause(@Form int form, String title, String message) { - mForm = form; - mTitle = title; - mMessage = message; - } - - public static void handleCause(Context context, IncapableCause cause) { - if (cause == null) - return; - - switch (cause.mForm) { - case NONE: - // do nothing. - break; - case DIALOG: - IncapableDialog incapableDialog = IncapableDialog.newInstance(cause.mTitle, cause.mMessage); - incapableDialog.show(((FragmentActivity) context).getSupportFragmentManager(), - IncapableDialog.class.getName()); - break; - case TOAST: - default: - Toast.makeText(context, cause.mMessage, Toast.LENGTH_SHORT).show(); - break; - } - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/entity/Item.java b/matisse/src/main/java/com/zhihu/matisse/internal/entity/Item.java deleted file mode 100644 index e854deb..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/entity/Item.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (C) 2014 nohana, Inc. - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.entity; - -import android.content.ContentUris; -import android.database.Cursor; -import android.net.Uri; -import android.os.Parcel; -import android.os.Parcelable; -import android.provider.MediaStore; -import android.support.annotation.Nullable; - -import com.zhihu.matisse.MimeType; - -public class Item implements Parcelable { - public static final Creator CREATOR = new Creator() { - @Override - @Nullable - public Item createFromParcel(Parcel source) { - return new Item(source); - } - - @Override - public Item[] newArray(int size) { - return new Item[size]; - } - }; - public static final long ITEM_ID_CAPTURE = -1; - public static final String ITEM_DISPLAY_NAME_CAPTURE = "Capture"; - public final long id; - public final String mimeType; - public final Uri uri; - public final long size; - public final long duration; // only for video, in ms - - private Item(long id, String mimeType, long size, long duration) { - this.id = id; - this.mimeType = mimeType; - Uri contentUri; - if (isImage()) { - contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; - } else if (isVideo()) { - contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; - } else { - // ? - contentUri = MediaStore.Files.getContentUri("external"); - } - this.uri = ContentUris.withAppendedId(contentUri, id); - this.size = size; - this.duration = duration; - } - - private Item(Parcel source) { - id = source.readLong(); - mimeType = source.readString(); - uri = source.readParcelable(Uri.class.getClassLoader()); - size = source.readLong(); - duration = source.readLong(); - } - - public static Item valueOf(Cursor cursor) { - return new Item(cursor.getLong(cursor.getColumnIndex(MediaStore.Files.FileColumns._ID)), - cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.MIME_TYPE)), - cursor.getLong(cursor.getColumnIndex(MediaStore.MediaColumns.SIZE)), - cursor.getLong(cursor.getColumnIndex("duration"))); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeLong(id); - dest.writeString(mimeType); - dest.writeParcelable(uri, 0); - dest.writeLong(size); - dest.writeLong(duration); - } - - public Uri getContentUri() { - return uri; - } - - public boolean isCapture() { - return id == ITEM_ID_CAPTURE; - } - - public boolean isImage() { - if (mimeType == null) return false; - return mimeType.equals(MimeType.JPEG.toString()) - || mimeType.equals(MimeType.PNG.toString()) - || mimeType.equals(MimeType.GIF.toString()) - || mimeType.equals(MimeType.BMP.toString()) - || mimeType.equals(MimeType.WEBP.toString()); - } - - public boolean isGif() { - if (mimeType == null) return false; - return mimeType.equals(MimeType.GIF.toString()); - } - - public boolean isVideo() { - if (mimeType == null) return false; - return mimeType.equals(MimeType.MPEG.toString()) - || mimeType.equals(MimeType.MP4.toString()) - || mimeType.equals(MimeType.QUICKTIME.toString()) - || mimeType.equals(MimeType.THREEGPP.toString()) - || mimeType.equals(MimeType.THREEGPP2.toString()) - || mimeType.equals(MimeType.MKV.toString()) - || mimeType.equals(MimeType.WEBM.toString()) - || mimeType.equals(MimeType.TS.toString()) - || mimeType.equals(MimeType.AVI.toString()); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof Item)) { - return false; - } - - Item other = (Item) obj; - return id == other.id - && (mimeType != null && mimeType.equals(other.mimeType) - || (mimeType == null && other.mimeType == null)) - && (uri != null && uri.equals(other.uri) - || (uri == null && other.uri == null)) - && size == other.size - && duration == other.duration; - } - - @Override - public int hashCode() { - int result = 1; - result = 31 * result + Long.valueOf(id).hashCode(); - if (mimeType != null) { - result = 31 * result + mimeType.hashCode(); - } - result = 31 * result + uri.hashCode(); - result = 31 * result + Long.valueOf(size).hashCode(); - result = 31 * result + Long.valueOf(duration).hashCode(); - return result; - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/entity/SelectionSpec.java b/matisse/src/main/java/com/zhihu/matisse/internal/entity/SelectionSpec.java deleted file mode 100644 index 77d28a9..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/entity/SelectionSpec.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2014 nohana, Inc. - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.entity; - -import android.content.pm.ActivityInfo; -import android.support.annotation.StyleRes; - -import com.zhihu.matisse.MimeType; -import com.zhihu.matisse.R; -import com.zhihu.matisse.engine.ImageEngine; -import com.zhihu.matisse.engine.impl.GlideEngine; -import com.zhihu.matisse.filter.Filter; -import com.zhihu.matisse.listener.OnCheckedListener; -import com.zhihu.matisse.listener.OnSelectedListener; - -import java.util.List; -import java.util.Set; - -public final class SelectionSpec { - - public Set mimeTypeSet; - public boolean mediaTypeExclusive; - public boolean showSingleMediaType; - @StyleRes - public int themeId; - public int orientation; - public boolean countable; - public int maxSelectable; - public int maxImageSelectable; - public int maxVideoSelectable; - public List filters; - public boolean capture; - public CaptureStrategy captureStrategy; - public int spanCount; - public int gridExpectedSize; - public float thumbnailScale; - public ImageEngine imageEngine; - public boolean hasInited; - public OnSelectedListener onSelectedListener; - public boolean originalable; - public boolean autoHideToobar; - public int originalMaxSize; - public OnCheckedListener onCheckedListener; - - private SelectionSpec() { - } - - public static SelectionSpec getInstance() { - return InstanceHolder.INSTANCE; - } - - public static SelectionSpec getCleanInstance() { - SelectionSpec selectionSpec = getInstance(); - selectionSpec.reset(); - return selectionSpec; - } - - private void reset() { - mimeTypeSet = null; - mediaTypeExclusive = true; - showSingleMediaType = false; - themeId = R.style.Matisse_Zhihu; - orientation = 0; - countable = false; - maxSelectable = 1; - maxImageSelectable = 0; - maxVideoSelectable = 0; - filters = null; - capture = false; - captureStrategy = null; - spanCount = 3; - gridExpectedSize = 0; - thumbnailScale = 0.5f; - imageEngine = new GlideEngine(); - hasInited = true; - originalable = false; - autoHideToobar = false; - originalMaxSize = Integer.MAX_VALUE; - } - - public boolean singleSelectionModeEnabled() { - return !countable && (maxSelectable == 1 || (maxImageSelectable == 1 && maxVideoSelectable == 1)); - } - - public boolean needOrientationRestriction() { - return orientation != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; - } - - public boolean onlyShowImages() { - return showSingleMediaType && MimeType.ofImage().containsAll(mimeTypeSet); - } - - public boolean onlyShowVideos() { - return showSingleMediaType && MimeType.ofVideo().containsAll(mimeTypeSet); - } - - private static final class InstanceHolder { - private static final SelectionSpec INSTANCE = new SelectionSpec(); - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/loader/AlbumLoader.java b/matisse/src/main/java/com/zhihu/matisse/internal/loader/AlbumLoader.java deleted file mode 100644 index f328296..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/loader/AlbumLoader.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2014 nohana, Inc. - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.loader; - -import android.content.Context; -import android.database.Cursor; -import android.database.MatrixCursor; -import android.database.MergeCursor; -import android.net.Uri; -import android.provider.MediaStore; -import android.support.v4.content.CursorLoader; - -import com.zhihu.matisse.internal.entity.Album; -import com.zhihu.matisse.internal.entity.SelectionSpec; - -/** - * Load all albums (grouped by bucket_id) into a single cursor. - */ -public class AlbumLoader extends CursorLoader { - public static final String COLUMN_COUNT = "count"; - private static final Uri QUERY_URI = MediaStore.Files.getContentUri("external"); - private static final String[] COLUMNS = { - MediaStore.Files.FileColumns._ID, - "bucket_id", - "bucket_display_name", - MediaStore.MediaColumns.DATA, - COLUMN_COUNT}; - private static final String[] PROJECTION = { - MediaStore.Files.FileColumns._ID, - "bucket_id", - "bucket_display_name", - MediaStore.MediaColumns.DATA, - "COUNT(*) AS " + COLUMN_COUNT}; - - // === params for showSingleMediaType: false === - private static final String SELECTION = - "(" + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?" - + " OR " - + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?)" - + " AND " + MediaStore.MediaColumns.SIZE + ">0" - + ") GROUP BY (bucket_id"; - private static final String[] SELECTION_ARGS = { - String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE), - String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO), - }; - // ============================================= - - // === params for showSingleMediaType: true === - private static final String SELECTION_FOR_SINGLE_MEDIA_TYPE = - MediaStore.Files.FileColumns.MEDIA_TYPE + "=?" - + " AND " + MediaStore.MediaColumns.SIZE + ">0" - + ") GROUP BY (bucket_id"; - - private static String[] getSelectionArgsForSingleMediaType(int mediaType) { - return new String[]{String.valueOf(mediaType)}; - } - // ============================================= - - private static final String BUCKET_ORDER_BY = "datetaken DESC"; - - private AlbumLoader(Context context, String selection, String[] selectionArgs) { - super(context, QUERY_URI, PROJECTION, selection, selectionArgs, BUCKET_ORDER_BY); - } - - public static CursorLoader newInstance(Context context) { - String selection; - String[] selectionArgs; - if (SelectionSpec.getInstance().onlyShowImages()) { - selection = SELECTION_FOR_SINGLE_MEDIA_TYPE; - selectionArgs = getSelectionArgsForSingleMediaType(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE); - } else if (SelectionSpec.getInstance().onlyShowVideos()) { - selection = SELECTION_FOR_SINGLE_MEDIA_TYPE; - selectionArgs = getSelectionArgsForSingleMediaType(MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO); - } else { - selection = SELECTION; - selectionArgs = SELECTION_ARGS; - } - return new AlbumLoader(context, selection, selectionArgs); - } - - @Override - public Cursor loadInBackground() { - Cursor albums = super.loadInBackground(); - MatrixCursor allAlbum = new MatrixCursor(COLUMNS); - int totalCount = 0; - String allAlbumCoverPath = ""; - if (albums != null) { - while (albums.moveToNext()) { - totalCount += albums.getInt(albums.getColumnIndex(COLUMN_COUNT)); - } - if (albums.moveToFirst()) { - allAlbumCoverPath = albums.getString(albums.getColumnIndex(MediaStore.MediaColumns.DATA)); - } - } - allAlbum.addRow(new String[]{Album.ALBUM_ID_ALL, Album.ALBUM_ID_ALL, Album.ALBUM_NAME_ALL, allAlbumCoverPath, - String.valueOf(totalCount)}); - - return new MergeCursor(new Cursor[]{allAlbum, albums}); - } - - @Override - public void onContentChanged() { - // FIXME a dirty way to fix loading multiple times - } -} \ No newline at end of file diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/loader/AlbumMediaLoader.java b/matisse/src/main/java/com/zhihu/matisse/internal/loader/AlbumMediaLoader.java deleted file mode 100644 index ea2b291..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/loader/AlbumMediaLoader.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (C) 2014 nohana, Inc. - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.loader; - -import android.content.Context; -import android.database.Cursor; -import android.database.MatrixCursor; -import android.database.MergeCursor; -import android.net.Uri; -import android.provider.MediaStore; -import android.support.v4.content.CursorLoader; - -import com.zhihu.matisse.internal.entity.Album; -import com.zhihu.matisse.internal.entity.Item; -import com.zhihu.matisse.internal.entity.SelectionSpec; -import com.zhihu.matisse.internal.utils.MediaStoreCompat; - -/** - * Load images and videos into a single cursor. - */ -public class AlbumMediaLoader extends CursorLoader { - private static final Uri QUERY_URI = MediaStore.Files.getContentUri("external"); - private static final String[] PROJECTION = { - MediaStore.Files.FileColumns._ID, - MediaStore.MediaColumns.DISPLAY_NAME, - MediaStore.MediaColumns.MIME_TYPE, - MediaStore.MediaColumns.SIZE, - "duration"}; - - // === params for album ALL && showSingleMediaType: false === - private static final String SELECTION_ALL = - "(" + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?" - + " OR " - + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?)" - + " AND " + MediaStore.MediaColumns.SIZE + ">0"; - private static final String[] SELECTION_ALL_ARGS = { - String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE), - String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO), - }; - // =========================================================== - - // === params for album ALL && showSingleMediaType: true === - private static final String SELECTION_ALL_FOR_SINGLE_MEDIA_TYPE = - MediaStore.Files.FileColumns.MEDIA_TYPE + "=?" - + " AND " + MediaStore.MediaColumns.SIZE + ">0"; - - private static String[] getSelectionArgsForSingleMediaType(int mediaType) { - return new String[]{String.valueOf(mediaType)}; - } - // ========================================================= - - // === params for ordinary album && showSingleMediaType: false === - private static final String SELECTION_ALBUM = - "(" + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?" - + " OR " - + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?)" - + " AND " - + " bucket_id=?" - + " AND " + MediaStore.MediaColumns.SIZE + ">0"; - - private static String[] getSelectionAlbumArgs(String albumId) { - return new String[]{ - String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE), - String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO), - albumId - }; - } - // =============================================================== - - // === params for ordinary album && showSingleMediaType: true === - private static final String SELECTION_ALBUM_FOR_SINGLE_MEDIA_TYPE = - MediaStore.Files.FileColumns.MEDIA_TYPE + "=?" - + " AND " - + " bucket_id=?" - + " AND " + MediaStore.MediaColumns.SIZE + ">0"; - - private static String[] getSelectionAlbumArgsForSingleMediaType(int mediaType, String albumId) { - return new String[]{String.valueOf(mediaType), albumId}; - } - // =============================================================== - - private static final String ORDER_BY = MediaStore.Images.Media.DATE_TAKEN + " DESC"; - private final boolean mEnableCapture; - - private AlbumMediaLoader(Context context, String selection, String[] selectionArgs, boolean capture) { - super(context, QUERY_URI, PROJECTION, selection, selectionArgs, ORDER_BY); - mEnableCapture = capture; - } - - public static CursorLoader newInstance(Context context, Album album, boolean capture) { - String selection; - String[] selectionArgs; - boolean enableCapture; - - if (album.isAll()) { - if (SelectionSpec.getInstance().onlyShowImages()) { - selection = SELECTION_ALL_FOR_SINGLE_MEDIA_TYPE; - selectionArgs = getSelectionArgsForSingleMediaType(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE); - } else if (SelectionSpec.getInstance().onlyShowVideos()) { - selection = SELECTION_ALL_FOR_SINGLE_MEDIA_TYPE; - selectionArgs = getSelectionArgsForSingleMediaType(MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO); - } else { - selection = SELECTION_ALL; - selectionArgs = SELECTION_ALL_ARGS; - } - enableCapture = capture; - } else { - if (SelectionSpec.getInstance().onlyShowImages()) { - selection = SELECTION_ALBUM_FOR_SINGLE_MEDIA_TYPE; - selectionArgs = getSelectionAlbumArgsForSingleMediaType(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE, - album.getId()); - } else if (SelectionSpec.getInstance().onlyShowVideos()) { - selection = SELECTION_ALBUM_FOR_SINGLE_MEDIA_TYPE; - selectionArgs = getSelectionAlbumArgsForSingleMediaType(MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO, - album.getId()); - } else { - selection = SELECTION_ALBUM; - selectionArgs = getSelectionAlbumArgs(album.getId()); - } - enableCapture = false; - } - return new AlbumMediaLoader(context, selection, selectionArgs, enableCapture); - } - - @Override - public Cursor loadInBackground() { - Cursor result = super.loadInBackground(); - if (!mEnableCapture || !MediaStoreCompat.hasCameraFeature(getContext())) { - return result; - } - MatrixCursor dummy = new MatrixCursor(PROJECTION); - dummy.addRow(new Object[]{Item.ITEM_ID_CAPTURE, Item.ITEM_DISPLAY_NAME_CAPTURE, "", 0, 0}); - return new MergeCursor(new Cursor[]{dummy, result}); - } - - @Override - public void onContentChanged() { - // FIXME a dirty way to fix loading multiple times - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/model/AlbumCollection.java b/matisse/src/main/java/com/zhihu/matisse/internal/model/AlbumCollection.java deleted file mode 100644 index bdfa925..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/model/AlbumCollection.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2014 nohana, Inc. - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.model; - -import android.content.Context; -import android.database.Cursor; -import android.os.Bundle; -import android.support.v4.app.FragmentActivity; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.Loader; - -import com.zhihu.matisse.internal.loader.AlbumLoader; - -import java.lang.ref.WeakReference; - -public class AlbumCollection implements LoaderManager.LoaderCallbacks { - private static final int LOADER_ID = 1; - private static final String STATE_CURRENT_SELECTION = "state_current_selection"; - private WeakReference mContext; - private LoaderManager mLoaderManager; - private AlbumCallbacks mCallbacks; - private int mCurrentSelection; - private boolean mLoadFinished; - - @Override - public Loader onCreateLoader(int id, Bundle args) { - Context context = mContext.get(); - if (context == null) { - return null; - } - mLoadFinished = false; - return AlbumLoader.newInstance(context); - } - - @Override - public void onLoadFinished(Loader loader, Cursor data) { - Context context = mContext.get(); - if (context == null) { - return; - } - - if (!mLoadFinished) { - mLoadFinished = true; - mCallbacks.onAlbumLoad(data); - } - } - - @Override - public void onLoaderReset(Loader loader) { - Context context = mContext.get(); - if (context == null) { - return; - } - - mCallbacks.onAlbumReset(); - } - - public void onCreate(FragmentActivity activity, AlbumCallbacks callbacks) { - mContext = new WeakReference(activity); - mLoaderManager = activity.getSupportLoaderManager(); - mCallbacks = callbacks; - } - - public void onRestoreInstanceState(Bundle savedInstanceState) { - if (savedInstanceState == null) { - return; - } - - mCurrentSelection = savedInstanceState.getInt(STATE_CURRENT_SELECTION); - } - - public void onSaveInstanceState(Bundle outState) { - outState.putInt(STATE_CURRENT_SELECTION, mCurrentSelection); - } - - public void onDestroy() { - if (mLoaderManager != null) { - mLoaderManager.destroyLoader(LOADER_ID); - } - mCallbacks = null; - } - - public void loadAlbums() { - mLoaderManager.initLoader(LOADER_ID, null, this); - } - - public int getCurrentSelection() { - return mCurrentSelection; - } - - public void setStateCurrentSelection(int currentSelection) { - mCurrentSelection = currentSelection; - } - - public interface AlbumCallbacks { - void onAlbumLoad(Cursor cursor); - - void onAlbumReset(); - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/model/AlbumMediaCollection.java b/matisse/src/main/java/com/zhihu/matisse/internal/model/AlbumMediaCollection.java deleted file mode 100644 index 90a938a..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/model/AlbumMediaCollection.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2014 nohana, Inc. - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.model; - -import android.content.Context; -import android.database.Cursor; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v4.app.FragmentActivity; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.Loader; - -import com.zhihu.matisse.internal.entity.Album; -import com.zhihu.matisse.internal.loader.AlbumMediaLoader; - -import java.lang.ref.WeakReference; - -public class AlbumMediaCollection implements LoaderManager.LoaderCallbacks { - private static final int LOADER_ID = 2; - private static final String ARGS_ALBUM = "args_album"; - private static final String ARGS_ENABLE_CAPTURE = "args_enable_capture"; - private WeakReference mContext; - private LoaderManager mLoaderManager; - private AlbumMediaCallbacks mCallbacks; - - @Override - public Loader onCreateLoader(int id, Bundle args) { - Context context = mContext.get(); - if (context == null) { - return null; - } - - Album album = args.getParcelable(ARGS_ALBUM); - if (album == null) { - return null; - } - - return AlbumMediaLoader.newInstance(context, album, - album.isAll() && args.getBoolean(ARGS_ENABLE_CAPTURE, false)); - } - - @Override - public void onLoadFinished(Loader loader, Cursor data) { - Context context = mContext.get(); - if (context == null) { - return; - } - - mCallbacks.onAlbumMediaLoad(data); - } - - @Override - public void onLoaderReset(Loader loader) { - Context context = mContext.get(); - if (context == null) { - return; - } - - mCallbacks.onAlbumMediaReset(); - } - - public void onCreate(@NonNull FragmentActivity context, @NonNull AlbumMediaCallbacks callbacks) { - mContext = new WeakReference(context); - mLoaderManager = context.getSupportLoaderManager(); - mCallbacks = callbacks; - } - - public void onDestroy() { - if (mLoaderManager != null) { - mLoaderManager.destroyLoader(LOADER_ID); - } - mCallbacks = null; - } - - public void load(@Nullable Album target) { - load(target, false); - } - - public void load(@Nullable Album target, boolean enableCapture) { - Bundle args = new Bundle(); - args.putParcelable(ARGS_ALBUM, target); - args.putBoolean(ARGS_ENABLE_CAPTURE, enableCapture); - mLoaderManager.initLoader(LOADER_ID, args, this); - } - - public interface AlbumMediaCallbacks { - - void onAlbumMediaLoad(Cursor cursor); - - void onAlbumMediaReset(); - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/model/SelectedItemCollection.java b/matisse/src/main/java/com/zhihu/matisse/internal/model/SelectedItemCollection.java deleted file mode 100644 index 7fdf690..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/model/SelectedItemCollection.java +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.model; - -import android.content.Context; -import android.content.res.Resources; -import android.net.Uri; -import android.os.Bundle; - -import com.zhihu.matisse.R; -import com.zhihu.matisse.internal.entity.IncapableCause; -import com.zhihu.matisse.internal.entity.Item; -import com.zhihu.matisse.internal.entity.SelectionSpec; -import com.zhihu.matisse.internal.ui.widget.CheckView; -import com.zhihu.matisse.internal.utils.PathUtils; -import com.zhihu.matisse.internal.utils.PhotoMetadataUtils; - -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; - -@SuppressWarnings("unused") -public class SelectedItemCollection { - - public static final String STATE_SELECTION = "state_selection"; - public static final String STATE_COLLECTION_TYPE = "state_collection_type"; - /** - * Empty collection - */ - public static final int COLLECTION_UNDEFINED = 0x00; - /** - * Collection only with images - */ - public static final int COLLECTION_IMAGE = 0x01; - /** - * Collection only with videos - */ - public static final int COLLECTION_VIDEO = 0x01 << 1; - /** - * Collection with images and videos. - */ - public static final int COLLECTION_MIXED = COLLECTION_IMAGE | COLLECTION_VIDEO; - private final Context mContext; - private Set mItems; - private int mCollectionType = COLLECTION_UNDEFINED; - - public SelectedItemCollection(Context context) { - mContext = context; - } - - public void onCreate(Bundle bundle) { - if (bundle == null) { - mItems = new LinkedHashSet<>(); - } else { - List saved = bundle.getParcelableArrayList(STATE_SELECTION); - mItems = new LinkedHashSet<>(saved); - mCollectionType = bundle.getInt(STATE_COLLECTION_TYPE, COLLECTION_UNDEFINED); - } - } - - public void setDefaultSelection(List uris) { - mItems.addAll(uris); - } - - public void onSaveInstanceState(Bundle outState) { - outState.putParcelableArrayList(STATE_SELECTION, new ArrayList<>(mItems)); - outState.putInt(STATE_COLLECTION_TYPE, mCollectionType); - } - - public Bundle getDataWithBundle() { - Bundle bundle = new Bundle(); - bundle.putParcelableArrayList(STATE_SELECTION, new ArrayList<>(mItems)); - bundle.putInt(STATE_COLLECTION_TYPE, mCollectionType); - return bundle; - } - - public boolean add(Item item) { - if (typeConflict(item)) { - throw new IllegalArgumentException("Can't select images and videos at the same time."); - } - boolean added = mItems.add(item); - if (added) { - if (mCollectionType == COLLECTION_UNDEFINED) { - if (item.isImage()) { - mCollectionType = COLLECTION_IMAGE; - } else if (item.isVideo()) { - mCollectionType = COLLECTION_VIDEO; - } - } else if (mCollectionType == COLLECTION_IMAGE) { - if (item.isVideo()) { - mCollectionType = COLLECTION_MIXED; - } - } else if (mCollectionType == COLLECTION_VIDEO) { - if (item.isImage()) { - mCollectionType = COLLECTION_MIXED; - } - } - } - return added; - } - - public boolean remove(Item item) { - boolean removed = mItems.remove(item); - if (removed) { - if (mItems.size() == 0) { - mCollectionType = COLLECTION_UNDEFINED; - } else { - if (mCollectionType == COLLECTION_MIXED) { - refineCollectionType(); - } - } - } - return removed; - } - - public void overwrite(ArrayList items, int collectionType) { - if (items.size() == 0) { - mCollectionType = COLLECTION_UNDEFINED; - } else { - mCollectionType = collectionType; - } - mItems.clear(); - mItems.addAll(items); - } - - - public List asList() { - return new ArrayList<>(mItems); - } - - public List asListOfUri() { - List uris = new ArrayList<>(); - for (Item item : mItems) { - uris.add(item.getContentUri()); - } - return uris; - } - - public List asListOfString() { - List paths = new ArrayList<>(); - for (Item item : mItems) { - paths.add(PathUtils.getPath(mContext, item.getContentUri())); - } - return paths; - } - - public boolean isEmpty() { - return mItems == null || mItems.isEmpty(); - } - - public boolean isSelected(Item item) { - return mItems.contains(item); - } - - public IncapableCause isAcceptable(Item item) { - if (maxSelectableReached()) { - int maxSelectable = currentMaxSelectable(); - String cause; - - try { - cause = mContext.getResources().getQuantityString( - R.plurals.error_over_count, - maxSelectable, - maxSelectable - ); - } catch (Resources.NotFoundException e) { - cause = mContext.getString( - R.string.error_over_count, - maxSelectable - ); - } catch (NoClassDefFoundError e) { - cause = mContext.getString( - R.string.error_over_count, - maxSelectable - ); - } - - return new IncapableCause(cause); - } else if (typeConflict(item)) { - return new IncapableCause(mContext.getString(R.string.error_type_conflict)); - } - - return PhotoMetadataUtils.isAcceptable(mContext, item); - } - - public boolean maxSelectableReached() { - return mItems.size() == currentMaxSelectable(); - } - - // depends - private int currentMaxSelectable() { - SelectionSpec spec = SelectionSpec.getInstance(); - if (spec.maxSelectable > 0) { - return spec.maxSelectable; - } else if (mCollectionType == COLLECTION_IMAGE) { - return spec.maxImageSelectable; - } else if (mCollectionType == COLLECTION_VIDEO) { - return spec.maxVideoSelectable; - } else { - return spec.maxSelectable; - } - } - - public int getCollectionType() { - return mCollectionType; - } - - private void refineCollectionType() { - boolean hasImage = false; - boolean hasVideo = false; - for (Item i : mItems) { - if (i.isImage() && !hasImage) hasImage = true; - if (i.isVideo() && !hasVideo) hasVideo = true; - } - if (hasImage && hasVideo) { - mCollectionType = COLLECTION_MIXED; - } else if (hasImage) { - mCollectionType = COLLECTION_IMAGE; - } else if (hasVideo) { - mCollectionType = COLLECTION_VIDEO; - } - } - - /** - * Determine whether there will be conflict media types. A user can only select images and videos at the same time - * while {@link SelectionSpec#mediaTypeExclusive} is set to false. - */ - public boolean typeConflict(Item item) { - return SelectionSpec.getInstance().mediaTypeExclusive - && ((item.isImage() && (mCollectionType == COLLECTION_VIDEO || mCollectionType == COLLECTION_MIXED)) - || (item.isVideo() && (mCollectionType == COLLECTION_IMAGE || mCollectionType == COLLECTION_MIXED))); - } - - public int count() { - return mItems.size(); - } - - public int checkedNumOf(Item item) { - int index = new ArrayList<>(mItems).indexOf(item); - return index == -1 ? CheckView.UNCHECKED : index + 1; - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/AlbumPreviewActivity.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/AlbumPreviewActivity.java deleted file mode 100644 index 73ff53e..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/AlbumPreviewActivity.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui; - -import android.database.Cursor; -import android.os.Bundle; -import android.support.annotation.Nullable; - -import com.zhihu.matisse.internal.entity.Album; -import com.zhihu.matisse.internal.entity.Item; -import com.zhihu.matisse.internal.entity.SelectionSpec; -import com.zhihu.matisse.internal.model.AlbumMediaCollection; -import com.zhihu.matisse.internal.ui.adapter.PreviewPagerAdapter; - -import java.util.ArrayList; -import java.util.List; - -public class AlbumPreviewActivity extends BasePreviewActivity implements - AlbumMediaCollection.AlbumMediaCallbacks { - - public static final String EXTRA_ALBUM = "extra_album"; - public static final String EXTRA_ITEM = "extra_item"; - - private AlbumMediaCollection mCollection = new AlbumMediaCollection(); - - private boolean mIsAlreadySetPosition; - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (!SelectionSpec.getInstance().hasInited) { - setResult(RESULT_CANCELED); - finish(); - return; - } - mCollection.onCreate(this, this); - Album album = getIntent().getParcelableExtra(EXTRA_ALBUM); - mCollection.load(album); - - Item item = getIntent().getParcelableExtra(EXTRA_ITEM); - if (mSpec.countable) { - mCheckView.setCheckedNum(mSelectedCollection.checkedNumOf(item)); - } else { - mCheckView.setChecked(mSelectedCollection.isSelected(item)); - } - updateSize(item); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - mCollection.onDestroy(); - } - - @Override - public void onAlbumMediaLoad(Cursor cursor) { - List items = new ArrayList<>(); - while (cursor.moveToNext()) { - items.add(Item.valueOf(cursor)); - } -// cursor.close(); - - if (items.isEmpty()) { - return; - } - - PreviewPagerAdapter adapter = (PreviewPagerAdapter) mPager.getAdapter(); - adapter.addAll(items); - adapter.notifyDataSetChanged(); - if (!mIsAlreadySetPosition) { - //onAlbumMediaLoad is called many times.. - mIsAlreadySetPosition = true; - Item selected = getIntent().getParcelableExtra(EXTRA_ITEM); - int selectedIndex = items.indexOf(selected); - mPager.setCurrentItem(selectedIndex, false); - mPreviousPos = selectedIndex; - } - } - - @Override - public void onAlbumMediaReset() { - - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/BasePreviewActivity.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/BasePreviewActivity.java deleted file mode 100644 index 82383fd..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/BasePreviewActivity.java +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui; - -import android.app.Activity; -import android.content.Intent; -import android.graphics.Color; -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.view.ViewPager; -import android.support.v4.view.animation.FastOutSlowInInterpolator; -import android.support.v7.app.AppCompatActivity; -import android.view.View; -import android.view.WindowManager; -import android.widget.FrameLayout; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.zhihu.matisse.R; -import com.zhihu.matisse.internal.entity.IncapableCause; -import com.zhihu.matisse.internal.entity.Item; -import com.zhihu.matisse.internal.entity.SelectionSpec; -import com.zhihu.matisse.internal.model.SelectedItemCollection; -import com.zhihu.matisse.internal.ui.adapter.PreviewPagerAdapter; -import com.zhihu.matisse.internal.ui.widget.CheckRadioView; -import com.zhihu.matisse.internal.ui.widget.CheckView; -import com.zhihu.matisse.internal.ui.widget.IncapableDialog; -import com.zhihu.matisse.internal.utils.PhotoMetadataUtils; -import com.zhihu.matisse.internal.utils.Platform; -import com.zhihu.matisse.listener.OnFragmentInteractionListener; - -public abstract class BasePreviewActivity extends AppCompatActivity implements View.OnClickListener, - ViewPager.OnPageChangeListener, OnFragmentInteractionListener { - - public static final String EXTRA_DEFAULT_BUNDLE = "extra_default_bundle"; - public static final String EXTRA_RESULT_BUNDLE = "extra_result_bundle"; - public static final String EXTRA_RESULT_APPLY = "extra_result_apply"; - public static final String EXTRA_RESULT_ORIGINAL_ENABLE = "extra_result_original_enable"; - public static final String CHECK_STATE = "checkState"; - - protected final SelectedItemCollection mSelectedCollection = new SelectedItemCollection(this); - protected SelectionSpec mSpec; - protected ViewPager mPager; - - protected PreviewPagerAdapter mAdapter; - - protected CheckView mCheckView; - protected TextView mButtonBack; - protected TextView mButtonApply; - protected TextView mSize; - - protected int mPreviousPos = -1; - - private LinearLayout mOriginalLayout; - private CheckRadioView mOriginal; - protected boolean mOriginalEnable; - - private FrameLayout mBottomToolbar; - private FrameLayout mTopToolbar; - private boolean mIsToolbarHide = false; - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - setTheme(SelectionSpec.getInstance().themeId); - super.onCreate(savedInstanceState); - if (!SelectionSpec.getInstance().hasInited) { - setResult(RESULT_CANCELED); - finish(); - return; - } - setContentView(R.layout.activity_media_preview); - if (Platform.hasKitKat()) { - getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); - } - - mSpec = SelectionSpec.getInstance(); - if (mSpec.needOrientationRestriction()) { - setRequestedOrientation(mSpec.orientation); - } - - if (savedInstanceState == null) { - mSelectedCollection.onCreate(getIntent().getBundleExtra(EXTRA_DEFAULT_BUNDLE)); - mOriginalEnable = getIntent().getBooleanExtra(EXTRA_RESULT_ORIGINAL_ENABLE, false); - } else { - mSelectedCollection.onCreate(savedInstanceState); - mOriginalEnable = savedInstanceState.getBoolean(CHECK_STATE); - } - mButtonBack = (TextView) findViewById(R.id.button_back); - mButtonApply = (TextView) findViewById(R.id.button_apply); - mSize = (TextView) findViewById(R.id.size); - mButtonBack.setOnClickListener(this); - mButtonApply.setOnClickListener(this); - - mPager = (ViewPager) findViewById(R.id.pager); - mPager.addOnPageChangeListener(this); - mAdapter = new PreviewPagerAdapter(getSupportFragmentManager(), null); - mPager.setAdapter(mAdapter); - mCheckView = (CheckView) findViewById(R.id.check_view); - mCheckView.setCountable(mSpec.countable); - mBottomToolbar = findViewById(R.id.bottom_toolbar); - mTopToolbar = findViewById(R.id.top_toolbar); - - mCheckView.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - Item item = mAdapter.getMediaItem(mPager.getCurrentItem()); - if (mSelectedCollection.isSelected(item)) { - mSelectedCollection.remove(item); - if (mSpec.countable) { - mCheckView.setCheckedNum(CheckView.UNCHECKED); - } else { - mCheckView.setChecked(false); - } - } else { - if (assertAddSelection(item)) { - mSelectedCollection.add(item); - if (mSpec.countable) { - mCheckView.setCheckedNum(mSelectedCollection.checkedNumOf(item)); - } else { - mCheckView.setChecked(true); - } - } - } - updateApplyButton(); - - if (mSpec.onSelectedListener != null) { - mSpec.onSelectedListener.onSelected( - mSelectedCollection.asListOfUri(), mSelectedCollection.asListOfString()); - } - } - }); - - - mOriginalLayout = findViewById(R.id.originalLayout); - mOriginal = findViewById(R.id.original); - mOriginalLayout.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - - int count = countOverMaxSize(); - if (count > 0) { - IncapableDialog incapableDialog = IncapableDialog.newInstance("", - getString(R.string.error_over_original_count, count, mSpec.originalMaxSize)); - incapableDialog.show(getSupportFragmentManager(), - IncapableDialog.class.getName()); - return; - } - - mOriginalEnable = !mOriginalEnable; - mOriginal.setChecked(mOriginalEnable); - if (!mOriginalEnable) { - mOriginal.setColor(Color.WHITE); - } - - - if (mSpec.onCheckedListener != null) { - mSpec.onCheckedListener.onCheck(mOriginalEnable); - } - } - }); - - updateApplyButton(); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - mSelectedCollection.onSaveInstanceState(outState); - outState.putBoolean("checkState", mOriginalEnable); - super.onSaveInstanceState(outState); - } - - @Override - public void onBackPressed() { - sendBackResult(false); - super.onBackPressed(); - } - - @Override - public void onClick(View v) { - if (v.getId() == R.id.button_back) { - onBackPressed(); - } else if (v.getId() == R.id.button_apply) { - sendBackResult(true); - finish(); - } - } - - @Override - public void onClick() { - if (!mSpec.autoHideToobar) { - return; - } - - if (mIsToolbarHide) { - mTopToolbar.animate() - .setInterpolator(new FastOutSlowInInterpolator()) - .translationYBy(mTopToolbar.getMeasuredHeight()) - .start(); - mBottomToolbar.animate() - .translationYBy(-mBottomToolbar.getMeasuredHeight()) - .setInterpolator(new FastOutSlowInInterpolator()) - .start(); - } else { - mTopToolbar.animate() - .setInterpolator(new FastOutSlowInInterpolator()) - .translationYBy(-mTopToolbar.getMeasuredHeight()) - .start(); - mBottomToolbar.animate() - .setInterpolator(new FastOutSlowInInterpolator()) - .translationYBy(mBottomToolbar.getMeasuredHeight()) - .start(); - } - - mIsToolbarHide = !mIsToolbarHide; - - } - - @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - - } - - @Override - public void onPageSelected(int position) { - PreviewPagerAdapter adapter = (PreviewPagerAdapter) mPager.getAdapter(); - if (mPreviousPos != -1 && mPreviousPos != position) { - ((PreviewItemFragment) adapter.instantiateItem(mPager, mPreviousPos)).resetView(); - - Item item = adapter.getMediaItem(position); - if (mSpec.countable) { - int checkedNum = mSelectedCollection.checkedNumOf(item); - mCheckView.setCheckedNum(checkedNum); - if (checkedNum > 0) { - mCheckView.setEnabled(true); - } else { - mCheckView.setEnabled(!mSelectedCollection.maxSelectableReached()); - } - } else { - boolean checked = mSelectedCollection.isSelected(item); - mCheckView.setChecked(checked); - if (checked) { - mCheckView.setEnabled(true); - } else { - mCheckView.setEnabled(!mSelectedCollection.maxSelectableReached()); - } - } - updateSize(item); - } - mPreviousPos = position; - } - - @Override - public void onPageScrollStateChanged(int state) { - - } - - private void updateApplyButton() { - int selectedCount = mSelectedCollection.count(); - if (selectedCount == 0) { - mButtonApply.setText(R.string.button_sure_default); - mButtonApply.setEnabled(false); - } else if (selectedCount == 1 && mSpec.singleSelectionModeEnabled()) { - mButtonApply.setText(R.string.button_sure_default); - mButtonApply.setEnabled(true); - } else { - mButtonApply.setEnabled(true); - mButtonApply.setText(getString(R.string.button_sure, selectedCount)); - } - - if (mSpec.originalable) { - mOriginalLayout.setVisibility(View.VISIBLE); - updateOriginalState(); - } else { - mOriginalLayout.setVisibility(View.GONE); - } - } - - - private void updateOriginalState() { - mOriginal.setChecked(mOriginalEnable); - if (!mOriginalEnable) { - mOriginal.setColor(Color.WHITE); - } - - if (countOverMaxSize() > 0) { - - if (mOriginalEnable) { - IncapableDialog incapableDialog = IncapableDialog.newInstance("", - getString(R.string.error_over_original_size, mSpec.originalMaxSize)); - incapableDialog.show(getSupportFragmentManager(), - IncapableDialog.class.getName()); - - mOriginal.setChecked(false); - mOriginal.setColor(Color.WHITE); - mOriginalEnable = false; - } - } - } - - - private int countOverMaxSize() { - int count = 0; - int selectedCount = mSelectedCollection.count(); - for (int i = 0; i < selectedCount; i++) { - Item item = mSelectedCollection.asList().get(i); - if (item.isImage()) { - float size = PhotoMetadataUtils.getSizeInMB(item.size); - if (size > mSpec.originalMaxSize) { - count++; - } - } - } - return count; - } - - protected void updateSize(Item item) { - if (item.isGif()) { - mSize.setVisibility(View.VISIBLE); - mSize.setText(PhotoMetadataUtils.getSizeInMB(item.size) + "M"); - } else { - mSize.setVisibility(View.GONE); - } - - if (item.isVideo()) { - mOriginalLayout.setVisibility(View.GONE); - } else if (mSpec.originalable) { - mOriginalLayout.setVisibility(View.VISIBLE); - } - } - - protected void sendBackResult(boolean apply) { - Intent intent = new Intent(); - intent.putExtra(EXTRA_RESULT_BUNDLE, mSelectedCollection.getDataWithBundle()); - intent.putExtra(EXTRA_RESULT_APPLY, apply); - intent.putExtra(EXTRA_RESULT_ORIGINAL_ENABLE, mOriginalEnable); - setResult(Activity.RESULT_OK, intent); - } - - private boolean assertAddSelection(Item item) { - IncapableCause cause = mSelectedCollection.isAcceptable(item); - IncapableCause.handleCause(this, cause); - return cause == null; - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/MediaSelectionFragment.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/MediaSelectionFragment.java deleted file mode 100644 index b00f09c..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/MediaSelectionFragment.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui; - -import android.content.Context; -import android.database.Cursor; -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; -import android.support.v7.widget.GridLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import com.zhihu.matisse.R; -import com.zhihu.matisse.internal.entity.Album; -import com.zhihu.matisse.internal.entity.Item; -import com.zhihu.matisse.internal.entity.SelectionSpec; -import com.zhihu.matisse.internal.model.AlbumMediaCollection; -import com.zhihu.matisse.internal.model.SelectedItemCollection; -import com.zhihu.matisse.internal.ui.adapter.AlbumMediaAdapter; -import com.zhihu.matisse.internal.ui.widget.MediaGridInset; -import com.zhihu.matisse.internal.utils.UIUtils; - -public class MediaSelectionFragment extends Fragment implements - AlbumMediaCollection.AlbumMediaCallbacks, AlbumMediaAdapter.CheckStateListener, - AlbumMediaAdapter.OnMediaClickListener { - - public static final String EXTRA_ALBUM = "extra_album"; - - private final AlbumMediaCollection mAlbumMediaCollection = new AlbumMediaCollection(); - private RecyclerView mRecyclerView; - private AlbumMediaAdapter mAdapter; - private SelectionProvider mSelectionProvider; - private AlbumMediaAdapter.CheckStateListener mCheckStateListener; - private AlbumMediaAdapter.OnMediaClickListener mOnMediaClickListener; - - public static MediaSelectionFragment newInstance(Album album) { - MediaSelectionFragment fragment = new MediaSelectionFragment(); - Bundle args = new Bundle(); - args.putParcelable(EXTRA_ALBUM, album); - fragment.setArguments(args); - return fragment; - } - - @Override - public void onAttach(Context context) { - super.onAttach(context); - if (context instanceof SelectionProvider) { - mSelectionProvider = (SelectionProvider) context; - } else { - throw new IllegalStateException("Context must implement SelectionProvider."); - } - if (context instanceof AlbumMediaAdapter.CheckStateListener) { - mCheckStateListener = (AlbumMediaAdapter.CheckStateListener) context; - } - if (context instanceof AlbumMediaAdapter.OnMediaClickListener) { - mOnMediaClickListener = (AlbumMediaAdapter.OnMediaClickListener) context; - } - } - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - return inflater.inflate(R.layout.fragment_media_selection, container, false); - } - - @Override - public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerview); - } - - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - Album album = getArguments().getParcelable(EXTRA_ALBUM); - - mAdapter = new AlbumMediaAdapter(getContext(), - mSelectionProvider.provideSelectedItemCollection(), mRecyclerView); - mAdapter.registerCheckStateListener(this); - mAdapter.registerOnMediaClickListener(this); - mRecyclerView.setHasFixedSize(true); - - int spanCount; - SelectionSpec selectionSpec = SelectionSpec.getInstance(); - if (selectionSpec.gridExpectedSize > 0) { - spanCount = UIUtils.spanCount(getContext(), selectionSpec.gridExpectedSize); - } else { - spanCount = selectionSpec.spanCount; - } - mRecyclerView.setLayoutManager(new GridLayoutManager(getContext(), spanCount)); - - int spacing = getResources().getDimensionPixelSize(R.dimen.media_grid_spacing); - mRecyclerView.addItemDecoration(new MediaGridInset(spanCount, spacing, false)); - mRecyclerView.setAdapter(mAdapter); - mAlbumMediaCollection.onCreate(getActivity(), this); - mAlbumMediaCollection.load(album, selectionSpec.capture); - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - mAlbumMediaCollection.onDestroy(); - } - - public void refreshMediaGrid() { - mAdapter.notifyDataSetChanged(); - } - - public void refreshSelection() { - mAdapter.refreshSelection(); - } - - @Override - public void onAlbumMediaLoad(Cursor cursor) { - mAdapter.swapCursor(cursor); - } - - @Override - public void onAlbumMediaReset() { - mAdapter.swapCursor(null); - } - - @Override - public void onUpdate() { - // notify outer Activity that check state changed - if (mCheckStateListener != null) { - mCheckStateListener.onUpdate(); - } - } - - @Override - public void onMediaClick(Album album, Item item, int adapterPosition) { - if (mOnMediaClickListener != null) { - mOnMediaClickListener.onMediaClick((Album) getArguments().getParcelable(EXTRA_ALBUM), - item, adapterPosition); - } - } - - public interface SelectionProvider { - SelectedItemCollection provideSelectedItemCollection(); - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/PreviewItemFragment.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/PreviewItemFragment.java deleted file mode 100644 index ef7fb12..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/PreviewItemFragment.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui; - -import android.content.ActivityNotFoundException; -import android.content.Context; -import android.content.Intent; -import android.graphics.Point; -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Toast; - -import com.zhihu.matisse.R; -import com.zhihu.matisse.internal.entity.Item; -import com.zhihu.matisse.internal.entity.SelectionSpec; -import com.zhihu.matisse.internal.utils.PhotoMetadataUtils; -import com.zhihu.matisse.listener.OnFragmentInteractionListener; - -import it.sephiroth.android.library.imagezoom.ImageViewTouch; -import it.sephiroth.android.library.imagezoom.ImageViewTouchBase; - -public class PreviewItemFragment extends Fragment { - - private static final String ARGS_ITEM = "args_item"; - private OnFragmentInteractionListener mListener; - - public static PreviewItemFragment newInstance(Item item) { - PreviewItemFragment fragment = new PreviewItemFragment(); - Bundle bundle = new Bundle(); - bundle.putParcelable(ARGS_ITEM, item); - fragment.setArguments(bundle); - return fragment; - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - return inflater.inflate(R.layout.fragment_preview_item, container, false); - } - - @Override - public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - final Item item = getArguments().getParcelable(ARGS_ITEM); - if (item == null) { - return; - } - - View videoPlayButton = view.findViewById(R.id.video_play_button); - if (item.isVideo()) { - videoPlayButton.setVisibility(View.VISIBLE); - videoPlayButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setDataAndType(item.uri, "video/*"); - try { - startActivity(intent); - } catch (ActivityNotFoundException e) { - Toast.makeText(getContext(), R.string.error_no_video_activity, Toast.LENGTH_SHORT).show(); - } - } - }); - } else { - videoPlayButton.setVisibility(View.GONE); - } - - ImageViewTouch image = (ImageViewTouch) view.findViewById(R.id.image_view); - image.setDisplayType(ImageViewTouchBase.DisplayType.FIT_TO_SCREEN); - - image.setSingleTapListener(new ImageViewTouch.OnImageViewTouchSingleTapListener() { - @Override - public void onSingleTapConfirmed() { - if (mListener != null) { - mListener.onClick(); - } - } - }); - - Point size = PhotoMetadataUtils.getBitmapSize(item.getContentUri(), getActivity()); - if (item.isGif()) { - SelectionSpec.getInstance().imageEngine.loadGifImage(getContext(), size.x, size.y, image, - item.getContentUri()); - } else { - SelectionSpec.getInstance().imageEngine.loadImage(getContext(), size.x, size.y, image, - item.getContentUri()); - } - } - - public void resetView() { - if (getView() != null) { - ((ImageViewTouch) getView().findViewById(R.id.image_view)).resetMatrix(); - } - } - - - @Override - public void onAttach(Context context) { - super.onAttach(context); - if (context instanceof OnFragmentInteractionListener) { - mListener = (OnFragmentInteractionListener) context; - } else { - throw new RuntimeException(context.toString() - + " must implement OnFragmentInteractionListener"); - } - } - - @Override - public void onDetach() { - super.onDetach(); - mListener = null; - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/SelectedPreviewActivity.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/SelectedPreviewActivity.java deleted file mode 100644 index 4bd6e25..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/SelectedPreviewActivity.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui; - -import android.os.Bundle; -import android.support.annotation.Nullable; - -import com.zhihu.matisse.internal.entity.Item; -import com.zhihu.matisse.internal.entity.SelectionSpec; -import com.zhihu.matisse.internal.model.SelectedItemCollection; - -import java.util.List; - -public class SelectedPreviewActivity extends BasePreviewActivity { - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (!SelectionSpec.getInstance().hasInited) { - setResult(RESULT_CANCELED); - finish(); - return; - } - - Bundle bundle = getIntent().getBundleExtra(EXTRA_DEFAULT_BUNDLE); - List selected = bundle.getParcelableArrayList(SelectedItemCollection.STATE_SELECTION); - mAdapter.addAll(selected); - mAdapter.notifyDataSetChanged(); - if (mSpec.countable) { - mCheckView.setCheckedNum(1); - } else { - mCheckView.setChecked(true); - } - mPreviousPos = 0; - updateSize(selected.get(0)); - } - -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/AlbumMediaAdapter.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/AlbumMediaAdapter.java deleted file mode 100644 index 769ba1b..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/AlbumMediaAdapter.java +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui.adapter; - -import android.content.Context; -import android.content.res.TypedArray; -import android.database.Cursor; -import android.graphics.PorterDuff; -import android.graphics.drawable.Drawable; -import android.support.v7.widget.GridLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; - -import com.zhihu.matisse.R; -import com.zhihu.matisse.internal.entity.Album; -import com.zhihu.matisse.internal.entity.Item; -import com.zhihu.matisse.internal.entity.SelectionSpec; -import com.zhihu.matisse.internal.entity.IncapableCause; -import com.zhihu.matisse.internal.model.SelectedItemCollection; -import com.zhihu.matisse.internal.ui.widget.CheckView; -import com.zhihu.matisse.internal.ui.widget.MediaGrid; - -public class AlbumMediaAdapter extends - RecyclerViewCursorAdapter implements - MediaGrid.OnMediaGridClickListener { - - private static final int VIEW_TYPE_CAPTURE = 0x01; - private static final int VIEW_TYPE_MEDIA = 0x02; - private final SelectedItemCollection mSelectedCollection; - private final Drawable mPlaceholder; - private SelectionSpec mSelectionSpec; - private CheckStateListener mCheckStateListener; - private OnMediaClickListener mOnMediaClickListener; - private RecyclerView mRecyclerView; - private int mImageResize; - - public AlbumMediaAdapter(Context context, SelectedItemCollection selectedCollection, RecyclerView recyclerView) { - super(null); - mSelectionSpec = SelectionSpec.getInstance(); - mSelectedCollection = selectedCollection; - - TypedArray ta = context.getTheme().obtainStyledAttributes(new int[]{R.attr.item_placeholder}); - mPlaceholder = ta.getDrawable(0); - ta.recycle(); - - mRecyclerView = recyclerView; - } - - @Override - public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - if (viewType == VIEW_TYPE_CAPTURE) { - View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.photo_capture_item, parent, false); - CaptureViewHolder holder = new CaptureViewHolder(v); - holder.itemView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (v.getContext() instanceof OnPhotoCapture) { - ((OnPhotoCapture) v.getContext()).capture(); - } - } - }); - return holder; - } else if (viewType == VIEW_TYPE_MEDIA) { - View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.media_grid_item, parent, false); - return new MediaViewHolder(v); - } - return null; - } - - @Override - protected void onBindViewHolder(final RecyclerView.ViewHolder holder, Cursor cursor) { - if (holder instanceof CaptureViewHolder) { - CaptureViewHolder captureViewHolder = (CaptureViewHolder) holder; - Drawable[] drawables = captureViewHolder.mHint.getCompoundDrawables(); - TypedArray ta = holder.itemView.getContext().getTheme().obtainStyledAttributes( - new int[]{R.attr.capture_textColor}); - int color = ta.getColor(0, 0); - ta.recycle(); - - for (int i = 0; i < drawables.length; i++) { - Drawable drawable = drawables[i]; - if (drawable != null) { - final Drawable.ConstantState state = drawable.getConstantState(); - if (state == null) { - continue; - } - - Drawable newDrawable = state.newDrawable().mutate(); - newDrawable.setColorFilter(color, PorterDuff.Mode.SRC_IN); - newDrawable.setBounds(drawable.getBounds()); - drawables[i] = newDrawable; - } - } - captureViewHolder.mHint.setCompoundDrawables(drawables[0], drawables[1], drawables[2], drawables[3]); - } else if (holder instanceof MediaViewHolder) { - MediaViewHolder mediaViewHolder = (MediaViewHolder) holder; - - final Item item = Item.valueOf(cursor); - mediaViewHolder.mMediaGrid.preBindMedia(new MediaGrid.PreBindInfo( - getImageResize(mediaViewHolder.mMediaGrid.getContext()), - mPlaceholder, - mSelectionSpec.countable, - holder - )); - mediaViewHolder.mMediaGrid.bindMedia(item); - mediaViewHolder.mMediaGrid.setOnMediaGridClickListener(this); - setCheckStatus(item, mediaViewHolder.mMediaGrid); - } - } - - private void setCheckStatus(Item item, MediaGrid mediaGrid) { - if (mSelectionSpec.countable) { - int checkedNum = mSelectedCollection.checkedNumOf(item); - if (checkedNum > 0) { - mediaGrid.setCheckEnabled(true); - mediaGrid.setCheckedNum(checkedNum); - } else { - if (mSelectedCollection.maxSelectableReached()) { - mediaGrid.setCheckEnabled(false); - mediaGrid.setCheckedNum(CheckView.UNCHECKED); - } else { - mediaGrid.setCheckEnabled(true); - mediaGrid.setCheckedNum(checkedNum); - } - } - } else { - boolean selected = mSelectedCollection.isSelected(item); - if (selected) { - mediaGrid.setCheckEnabled(true); - mediaGrid.setChecked(true); - } else { - if (mSelectedCollection.maxSelectableReached()) { - mediaGrid.setCheckEnabled(false); - mediaGrid.setChecked(false); - } else { - mediaGrid.setCheckEnabled(true); - mediaGrid.setChecked(false); - } - } - } - } - - @Override - public void onThumbnailClicked(ImageView thumbnail, Item item, RecyclerView.ViewHolder holder) { - if (mOnMediaClickListener != null) { - mOnMediaClickListener.onMediaClick(null, item, holder.getAdapterPosition()); - } - } - - @Override - public void onCheckViewClicked(CheckView checkView, Item item, RecyclerView.ViewHolder holder) { - if (mSelectionSpec.countable) { - int checkedNum = mSelectedCollection.checkedNumOf(item); - if (checkedNum == CheckView.UNCHECKED) { - if (assertAddSelection(holder.itemView.getContext(), item)) { - mSelectedCollection.add(item); - notifyCheckStateChanged(); - } - } else { - mSelectedCollection.remove(item); - notifyCheckStateChanged(); - } - } else { - if (mSelectedCollection.isSelected(item)) { - mSelectedCollection.remove(item); - notifyCheckStateChanged(); - } else { - if (assertAddSelection(holder.itemView.getContext(), item)) { - mSelectedCollection.add(item); - notifyCheckStateChanged(); - } - } - } - } - - private void notifyCheckStateChanged() { - notifyDataSetChanged(); - if (mCheckStateListener != null) { - mCheckStateListener.onUpdate(); - } - } - - @Override - public int getItemViewType(int position, Cursor cursor) { - return Item.valueOf(cursor).isCapture() ? VIEW_TYPE_CAPTURE : VIEW_TYPE_MEDIA; - } - - private boolean assertAddSelection(Context context, Item item) { - IncapableCause cause = mSelectedCollection.isAcceptable(item); - IncapableCause.handleCause(context, cause); - return cause == null; - } - - - public void registerCheckStateListener(CheckStateListener listener) { - mCheckStateListener = listener; - } - - public void unregisterCheckStateListener() { - mCheckStateListener = null; - } - - public void registerOnMediaClickListener(OnMediaClickListener listener) { - mOnMediaClickListener = listener; - } - - public void unregisterOnMediaClickListener() { - mOnMediaClickListener = null; - } - - public void refreshSelection() { - GridLayoutManager layoutManager = (GridLayoutManager) mRecyclerView.getLayoutManager(); - int first = layoutManager.findFirstVisibleItemPosition(); - int last = layoutManager.findLastVisibleItemPosition(); - if (first == -1 || last == -1) { - return; - } - Cursor cursor = getCursor(); - for (int i = first; i <= last; i++) { - RecyclerView.ViewHolder holder = mRecyclerView.findViewHolderForAdapterPosition(first); - if (holder instanceof MediaViewHolder) { - if (cursor.moveToPosition(i)) { - setCheckStatus(Item.valueOf(cursor), ((MediaViewHolder) holder).mMediaGrid); - } - } - } - } - - private int getImageResize(Context context) { - if (mImageResize == 0) { - RecyclerView.LayoutManager lm = mRecyclerView.getLayoutManager(); - int spanCount = ((GridLayoutManager) lm).getSpanCount(); - int screenWidth = context.getResources().getDisplayMetrics().widthPixels; - int availableWidth = screenWidth - context.getResources().getDimensionPixelSize( - R.dimen.media_grid_spacing) * (spanCount - 1); - mImageResize = availableWidth / spanCount; - mImageResize = (int) (mImageResize * mSelectionSpec.thumbnailScale); - } - return mImageResize; - } - - public interface CheckStateListener { - void onUpdate(); - } - - public interface OnMediaClickListener { - void onMediaClick(Album album, Item item, int adapterPosition); - } - - public interface OnPhotoCapture { - void capture(); - } - - private static class MediaViewHolder extends RecyclerView.ViewHolder { - - private MediaGrid mMediaGrid; - - MediaViewHolder(View itemView) { - super(itemView); - mMediaGrid = (MediaGrid) itemView; - } - } - - private static class CaptureViewHolder extends RecyclerView.ViewHolder { - - private TextView mHint; - - CaptureViewHolder(View itemView) { - super(itemView); - - mHint = (TextView) itemView.findViewById(R.id.hint); - } - } - -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/AlbumsAdapter.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/AlbumsAdapter.java deleted file mode 100644 index 711e512..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/AlbumsAdapter.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui.adapter; - -import android.content.Context; -import android.content.res.TypedArray; -import android.database.Cursor; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.CursorAdapter; -import android.widget.ImageView; -import android.widget.TextView; - -import com.zhihu.matisse.R; -import com.zhihu.matisse.internal.entity.Album; -import com.zhihu.matisse.internal.entity.SelectionSpec; - -import java.io.File; - -public class AlbumsAdapter extends CursorAdapter { - - private final Drawable mPlaceholder; - - public AlbumsAdapter(Context context, Cursor c, boolean autoRequery) { - super(context, c, autoRequery); - - TypedArray ta = context.getTheme().obtainStyledAttributes( - new int[]{R.attr.album_thumbnail_placeholder}); - mPlaceholder = ta.getDrawable(0); - ta.recycle(); - } - - public AlbumsAdapter(Context context, Cursor c, int flags) { - super(context, c, flags); - - TypedArray ta = context.getTheme().obtainStyledAttributes( - new int[]{R.attr.album_thumbnail_placeholder}); - mPlaceholder = ta.getDrawable(0); - ta.recycle(); - } - - @Override - public View newView(Context context, Cursor cursor, ViewGroup parent) { - return LayoutInflater.from(context).inflate(R.layout.album_list_item, parent, false); - } - - @Override - public void bindView(View view, Context context, Cursor cursor) { - Album album = Album.valueOf(cursor); - ((TextView) view.findViewById(R.id.album_name)).setText(album.getDisplayName(context)); - ((TextView) view.findViewById(R.id.album_media_count)).setText(String.valueOf(album.getCount())); - - // do not need to load animated Gif - SelectionSpec.getInstance().imageEngine.loadThumbnail(context, context.getResources().getDimensionPixelSize(R - .dimen.media_grid_size), mPlaceholder, - (ImageView) view.findViewById(R.id.album_cover), Uri.fromFile(new File(album.getCoverPath()))); - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/PreviewPagerAdapter.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/PreviewPagerAdapter.java deleted file mode 100644 index eef46f0..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/PreviewPagerAdapter.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui.adapter; - -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentPagerAdapter; -import android.view.ViewGroup; - -import com.zhihu.matisse.internal.entity.Item; -import com.zhihu.matisse.internal.ui.PreviewItemFragment; - -import java.util.ArrayList; -import java.util.List; - -public class PreviewPagerAdapter extends FragmentPagerAdapter { - - private ArrayList mItems = new ArrayList<>(); - private OnPrimaryItemSetListener mListener; - - public PreviewPagerAdapter(FragmentManager manager, OnPrimaryItemSetListener listener) { - super(manager); - mListener = listener; - } - - @Override - public Fragment getItem(int position) { - return PreviewItemFragment.newInstance(mItems.get(position)); - } - - @Override - public int getCount() { - return mItems.size(); - } - - @Override - public void setPrimaryItem(ViewGroup container, int position, Object object) { - super.setPrimaryItem(container, position, object); - if (mListener != null) { - mListener.onPrimaryItemSet(position); - } - } - - public Item getMediaItem(int position) { - return mItems.get(position); - } - - public void addAll(List items) { - mItems.addAll(items); - } - - interface OnPrimaryItemSetListener { - - void onPrimaryItemSet(int position); - } - -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/RecyclerViewCursorAdapter.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/RecyclerViewCursorAdapter.java deleted file mode 100644 index 6557dde..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/adapter/RecyclerViewCursorAdapter.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui.adapter; - -import android.database.Cursor; -import android.provider.MediaStore; -import android.support.v7.widget.RecyclerView; - -public abstract class RecyclerViewCursorAdapter extends - RecyclerView.Adapter { - - private Cursor mCursor; - private int mRowIDColumn; - - RecyclerViewCursorAdapter(Cursor c) { - setHasStableIds(true); - swapCursor(c); - } - - protected abstract void onBindViewHolder(VH holder, Cursor cursor); - - @Override - public void onBindViewHolder(VH holder, int position) { - if (!isDataValid(mCursor)) { - throw new IllegalStateException("Cannot bind view holder when cursor is in invalid state."); - } - if (!mCursor.moveToPosition(position)) { - throw new IllegalStateException("Could not move cursor to position " + position - + " when trying to bind view holder"); - } - - onBindViewHolder(holder, mCursor); - } - - @Override - public int getItemViewType(int position) { - if (!mCursor.moveToPosition(position)) { - throw new IllegalStateException("Could not move cursor to position " + position - + " when trying to get item view type."); - } - return getItemViewType(position, mCursor); - } - - protected abstract int getItemViewType(int position, Cursor cursor); - - @Override - public int getItemCount() { - if (isDataValid(mCursor)) { - return mCursor.getCount(); - } else { - return 0; - } - } - - @Override - public long getItemId(int position) { - if (!isDataValid(mCursor)) { - throw new IllegalStateException("Cannot lookup item id when cursor is in invalid state."); - } - if (!mCursor.moveToPosition(position)) { - throw new IllegalStateException("Could not move cursor to position " + position - + " when trying to get an item id"); - } - - return mCursor.getLong(mRowIDColumn); - } - - public void swapCursor(Cursor newCursor) { - if (newCursor == mCursor) { - return; - } - - if (newCursor != null) { - mCursor = newCursor; - mRowIDColumn = mCursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns._ID); - // notify the observers about the new cursor - notifyDataSetChanged(); - } else { - notifyItemRangeRemoved(0, getItemCount()); - mCursor = null; - mRowIDColumn = -1; - } - } - - public Cursor getCursor() { - return mCursor; - } - - private boolean isDataValid(Cursor cursor) { - return cursor != null && !cursor.isClosed(); - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/AlbumsSpinner.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/AlbumsSpinner.java deleted file mode 100644 index b3c9534..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/AlbumsSpinner.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui.widget; - -import android.content.Context; -import android.content.res.TypedArray; -import android.database.Cursor; -import android.graphics.PorterDuff; -import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; -import android.support.v7.widget.ListPopupWindow; -import android.view.View; -import android.widget.AdapterView; -import android.widget.CursorAdapter; -import android.widget.TextView; - -import com.zhihu.matisse.R; -import com.zhihu.matisse.internal.entity.Album; -import com.zhihu.matisse.internal.utils.Platform; - -public class AlbumsSpinner { - - private static final int MAX_SHOWN_COUNT = 6; - private CursorAdapter mAdapter; - private TextView mSelected; - private ListPopupWindow mListPopupWindow; - private AdapterView.OnItemSelectedListener mOnItemSelectedListener; - - public AlbumsSpinner(@NonNull Context context) { - mListPopupWindow = new ListPopupWindow(context, null, R.attr.listPopupWindowStyle); - mListPopupWindow.setModal(true); - float density = context.getResources().getDisplayMetrics().density; - mListPopupWindow.setContentWidth((int) (216 * density)); - mListPopupWindow.setHorizontalOffset((int) (16 * density)); - mListPopupWindow.setVerticalOffset((int) (-48 * density)); - - mListPopupWindow.setOnItemClickListener(new AdapterView.OnItemClickListener() { - - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - AlbumsSpinner.this.onItemSelected(parent.getContext(), position); - if (mOnItemSelectedListener != null) { - mOnItemSelectedListener.onItemSelected(parent, view, position, id); - } - } - }); - } - - public void setOnItemSelectedListener(AdapterView.OnItemSelectedListener listener) { - mOnItemSelectedListener = listener; - } - - public void setSelection(Context context, int position) { - mListPopupWindow.setSelection(position); - onItemSelected(context, position); - } - - private void onItemSelected(Context context, int position) { - mListPopupWindow.dismiss(); - Cursor cursor = mAdapter.getCursor(); - cursor.moveToPosition(position); - Album album = Album.valueOf(cursor); - String displayName = album.getDisplayName(context); - if (mSelected.getVisibility() == View.VISIBLE) { - mSelected.setText(displayName); - } else { - if (Platform.hasICS()) { - mSelected.setAlpha(0.0f); - mSelected.setVisibility(View.VISIBLE); - mSelected.setText(displayName); - mSelected.animate().alpha(1.0f).setDuration(context.getResources().getInteger( - android.R.integer.config_longAnimTime)).start(); - } else { - mSelected.setVisibility(View.VISIBLE); - mSelected.setText(displayName); - } - - } - } - - public void setAdapter(CursorAdapter adapter) { - mListPopupWindow.setAdapter(adapter); - mAdapter = adapter; - } - - public void setSelectedTextView(TextView textView) { - mSelected = textView; - // tint dropdown arrow icon - Drawable[] drawables = mSelected.getCompoundDrawables(); - Drawable right = drawables[2]; - TypedArray ta = mSelected.getContext().getTheme().obtainStyledAttributes( - new int[]{R.attr.album_element_color}); - int color = ta.getColor(0, 0); - ta.recycle(); - right.setColorFilter(color, PorterDuff.Mode.SRC_IN); - - mSelected.setVisibility(View.GONE); - mSelected.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - int itemHeight = v.getResources().getDimensionPixelSize(R.dimen.album_item_height); - mListPopupWindow.setHeight( - mAdapter.getCount() > MAX_SHOWN_COUNT ? itemHeight * MAX_SHOWN_COUNT - : itemHeight * mAdapter.getCount()); - mListPopupWindow.show(); - } - }); - mSelected.setOnTouchListener(mListPopupWindow.createDragToOpenListener(mSelected)); - } - - public void setPopupAnchorView(View view) { - mListPopupWindow.setAnchorView(view); - } - -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/CheckRadioView.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/CheckRadioView.java deleted file mode 100644 index f860c58..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/CheckRadioView.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.zhihu.matisse.internal.ui.widget; - -import android.content.Context; -import android.graphics.PorterDuff; -import android.graphics.drawable.Drawable; -import android.support.v4.content.res.ResourcesCompat; -import android.support.v7.widget.AppCompatImageView; -import android.util.AttributeSet; - -import com.zhihu.matisse.R; - -public class CheckRadioView extends AppCompatImageView { - - private Drawable mDrawable; - - private int mSelectedColor; - private int mUnSelectUdColor; - - public CheckRadioView(Context context) { - super(context); - init(); - } - - - - public CheckRadioView(Context context, AttributeSet attrs) { - super(context, attrs); - init(); - } - - private void init() { - mSelectedColor = ResourcesCompat.getColor( - getResources(), R.color.zhihu_item_checkCircle_backgroundColor, - getContext().getTheme()); - mUnSelectUdColor = ResourcesCompat.getColor( - getResources(), R.color.zhihu_check_original_radio_disable, - getContext().getTheme()); - setChecked(false); - } - - public void setChecked(boolean enable) { - if (enable) { - setImageResource(R.drawable.ic_preview_radio_on); - mDrawable = getDrawable(); - mDrawable.setColorFilter(mSelectedColor, PorterDuff.Mode.SRC_IN); - } else { - setImageResource(R.drawable.ic_preview_radio_off); - mDrawable = getDrawable(); - mDrawable.setColorFilter(mUnSelectUdColor, PorterDuff.Mode.SRC_IN); - } - } - - - public void setColor(int color) { - if (mDrawable == null) { - mDrawable = getDrawable(); - } - mDrawable.setColorFilter(color, PorterDuff.Mode.SRC_IN); - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/CheckView.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/CheckView.java deleted file mode 100644 index b958113..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/CheckView.java +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui.widget; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffXfermode; -import android.graphics.RadialGradient; -import android.graphics.Rect; -import android.graphics.Shader; -import android.graphics.Typeface; -import android.graphics.drawable.Drawable; -import android.support.v4.content.res.ResourcesCompat; -import android.text.TextPaint; -import android.util.AttributeSet; -import android.view.View; - -import com.zhihu.matisse.R; - -public class CheckView extends View { - - public static final int UNCHECKED = Integer.MIN_VALUE; - private static final float STROKE_WIDTH = 3.0f; // dp - private static final float SHADOW_WIDTH = 6.0f; // dp - private static final int SIZE = 48; // dp - private static final float STROKE_RADIUS = 11.5f; // dp - private static final float BG_RADIUS = 11.0f; // dp - private static final int CONTENT_SIZE = 16; // dp - private boolean mCountable; - private boolean mChecked; - private int mCheckedNum; - private Paint mStrokePaint; - private Paint mBackgroundPaint; - private TextPaint mTextPaint; - private Paint mShadowPaint; - private Drawable mCheckDrawable; - private float mDensity; - private Rect mCheckRect; - private boolean mEnabled = true; - - public CheckView(Context context) { - super(context); - init(context); - } - - public CheckView(Context context, AttributeSet attrs) { - super(context, attrs); - init(context); - } - - public CheckView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - init(context); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - // fixed size 48dp x 48dp - int sizeSpec = MeasureSpec.makeMeasureSpec((int) (SIZE * mDensity), MeasureSpec.EXACTLY); - super.onMeasure(sizeSpec, sizeSpec); - } - - private void init(Context context) { - mDensity = context.getResources().getDisplayMetrics().density; - - mStrokePaint = new Paint(); - mStrokePaint.setAntiAlias(true); - mStrokePaint.setStyle(Paint.Style.STROKE); - mStrokePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER)); - mStrokePaint.setStrokeWidth(STROKE_WIDTH * mDensity); - TypedArray ta = getContext().getTheme().obtainStyledAttributes(new int[]{R.attr.item_checkCircle_borderColor}); - int defaultColor = ResourcesCompat.getColor( - getResources(), R.color.zhihu_item_checkCircle_borderColor, - getContext().getTheme()); - int color = ta.getColor(0, defaultColor); - ta.recycle(); - mStrokePaint.setColor(color); - - mCheckDrawable = ResourcesCompat.getDrawable(context.getResources(), - R.drawable.ic_check_white_18dp, context.getTheme()); - } - - public void setChecked(boolean checked) { - if (mCountable) { - throw new IllegalStateException("CheckView is countable, call setCheckedNum() instead."); - } - mChecked = checked; - invalidate(); - } - - public void setCountable(boolean countable) { - mCountable = countable; - } - - public void setCheckedNum(int checkedNum) { - if (!mCountable) { - throw new IllegalStateException("CheckView is not countable, call setChecked() instead."); - } - if (checkedNum != UNCHECKED && checkedNum <= 0) { - throw new IllegalArgumentException("checked num can't be negative."); - } - mCheckedNum = checkedNum; - invalidate(); - } - - public void setEnabled(boolean enabled) { - if (mEnabled != enabled) { - mEnabled = enabled; - invalidate(); - } - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - - // draw outer and inner shadow - initShadowPaint(); - canvas.drawCircle((float) SIZE * mDensity / 2, (float) SIZE * mDensity / 2, - (STROKE_RADIUS + STROKE_WIDTH / 2 + SHADOW_WIDTH) * mDensity, mShadowPaint); - - // draw white stroke - canvas.drawCircle((float) SIZE * mDensity / 2, (float) SIZE * mDensity / 2, - STROKE_RADIUS * mDensity, mStrokePaint); - - // draw content - if (mCountable) { - if (mCheckedNum != UNCHECKED) { - initBackgroundPaint(); - canvas.drawCircle((float) SIZE * mDensity / 2, (float) SIZE * mDensity / 2, - BG_RADIUS * mDensity, mBackgroundPaint); - initTextPaint(); - String text = String.valueOf(mCheckedNum); - int baseX = (int) (canvas.getWidth() - mTextPaint.measureText(text)) / 2; - int baseY = (int) (canvas.getHeight() - mTextPaint.descent() - mTextPaint.ascent()) / 2; - canvas.drawText(text, baseX, baseY, mTextPaint); - } - } else { - if (mChecked) { - initBackgroundPaint(); - canvas.drawCircle((float) SIZE * mDensity / 2, (float) SIZE * mDensity / 2, - BG_RADIUS * mDensity, mBackgroundPaint); - - mCheckDrawable.setBounds(getCheckRect()); - mCheckDrawable.draw(canvas); - } - } - - // enable hint - setAlpha(mEnabled ? 1.0f : 0.5f); - } - - private void initShadowPaint() { - if (mShadowPaint == null) { - mShadowPaint = new Paint(); - mShadowPaint.setAntiAlias(true); - // all in dp - float outerRadius = STROKE_RADIUS + STROKE_WIDTH / 2; - float innerRadius = outerRadius - STROKE_WIDTH; - float gradientRadius = outerRadius + SHADOW_WIDTH; - float stop0 = (innerRadius - SHADOW_WIDTH) / gradientRadius; - float stop1 = innerRadius / gradientRadius; - float stop2 = outerRadius / gradientRadius; - float stop3 = 1.0f; - mShadowPaint.setShader( - new RadialGradient((float) SIZE * mDensity / 2, - (float) SIZE * mDensity / 2, - gradientRadius * mDensity, - new int[]{Color.parseColor("#00000000"), Color.parseColor("#0D000000"), - Color.parseColor("#0D000000"), Color.parseColor("#00000000")}, - new float[]{stop0, stop1, stop2, stop3}, - Shader.TileMode.CLAMP)); - } - } - - private void initBackgroundPaint() { - if (mBackgroundPaint == null) { - mBackgroundPaint = new Paint(); - mBackgroundPaint.setAntiAlias(true); - mBackgroundPaint.setStyle(Paint.Style.FILL); - TypedArray ta = getContext().getTheme() - .obtainStyledAttributes(new int[]{R.attr.item_checkCircle_backgroundColor}); - int defaultColor = ResourcesCompat.getColor( - getResources(), R.color.zhihu_item_checkCircle_backgroundColor, - getContext().getTheme()); - int color = ta.getColor(0, defaultColor); - ta.recycle(); - mBackgroundPaint.setColor(color); - } - } - - private void initTextPaint() { - if (mTextPaint == null) { - mTextPaint = new TextPaint(); - mTextPaint.setAntiAlias(true); - mTextPaint.setColor(Color.WHITE); - mTextPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD)); - mTextPaint.setTextSize(12.0f * mDensity); - } - } - - // rect for drawing checked number or mark - private Rect getCheckRect() { - if (mCheckRect == null) { - int rectPadding = (int) (SIZE * mDensity / 2 - CONTENT_SIZE * mDensity / 2); - mCheckRect = new Rect(rectPadding, rectPadding, - (int) (SIZE * mDensity - rectPadding), (int) (SIZE * mDensity - rectPadding)); - } - - return mCheckRect; - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/IncapableDialog.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/IncapableDialog.java deleted file mode 100644 index 1599fce..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/IncapableDialog.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui.widget; - -import android.app.Dialog; -import android.content.DialogInterface; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.DialogFragment; -import android.support.v7.app.AlertDialog; -import android.text.TextUtils; - -import com.zhihu.matisse.R; - -public class IncapableDialog extends DialogFragment { - - public static final String EXTRA_TITLE = "extra_title"; - public static final String EXTRA_MESSAGE = "extra_message"; - - public static IncapableDialog newInstance(String title, String message) { - IncapableDialog dialog = new IncapableDialog(); - Bundle args = new Bundle(); - args.putString(EXTRA_TITLE, title); - args.putString(EXTRA_MESSAGE, message); - dialog.setArguments(args); - return dialog; - } - - @NonNull - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - String title = getArguments().getString(EXTRA_TITLE); - String message = getArguments().getString(EXTRA_MESSAGE); - - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - if (!TextUtils.isEmpty(title)) { - builder.setTitle(title); - } - if (!TextUtils.isEmpty(message)) { - builder.setMessage(message); - } - builder.setPositiveButton(R.string.button_ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - } - }); - - return builder.create(); - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/MediaGrid.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/MediaGrid.java deleted file mode 100644 index a7c2662..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/MediaGrid.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui.widget; - -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.support.v7.widget.RecyclerView; -import android.text.format.DateUtils; -import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.ImageView; -import android.widget.TextView; - -import com.zhihu.matisse.R; -import com.zhihu.matisse.internal.entity.Item; -import com.zhihu.matisse.internal.entity.SelectionSpec; - -public class MediaGrid extends SquareFrameLayout implements View.OnClickListener { - - private ImageView mThumbnail; - private CheckView mCheckView; - private ImageView mGifTag; - private TextView mVideoDuration; - - private Item mMedia; - private PreBindInfo mPreBindInfo; - private OnMediaGridClickListener mListener; - - public MediaGrid(Context context) { - super(context); - init(context); - } - - public MediaGrid(Context context, AttributeSet attrs) { - super(context, attrs); - init(context); - } - - private void init(Context context) { - LayoutInflater.from(context).inflate(R.layout.media_grid_content, this, true); - - mThumbnail = (ImageView) findViewById(R.id.media_thumbnail); - mCheckView = (CheckView) findViewById(R.id.check_view); - mGifTag = (ImageView) findViewById(R.id.gif); - mVideoDuration = (TextView) findViewById(R.id.video_duration); - - mThumbnail.setOnClickListener(this); - mCheckView.setOnClickListener(this); - } - - @Override - public void onClick(View v) { - if (mListener != null) { - if (v == mThumbnail) { - mListener.onThumbnailClicked(mThumbnail, mMedia, mPreBindInfo.mViewHolder); - } else if (v == mCheckView) { - mListener.onCheckViewClicked(mCheckView, mMedia, mPreBindInfo.mViewHolder); - } - } - } - - public void preBindMedia(PreBindInfo info) { - mPreBindInfo = info; - } - - public void bindMedia(Item item) { - mMedia = item; - setGifTag(); - initCheckView(); - setImage(); - setVideoDuration(); - } - - public Item getMedia() { - return mMedia; - } - - private void setGifTag() { - mGifTag.setVisibility(mMedia.isGif() ? View.VISIBLE : View.GONE); - } - - private void initCheckView() { - mCheckView.setCountable(mPreBindInfo.mCheckViewCountable); - } - - public void setCheckEnabled(boolean enabled) { - mCheckView.setEnabled(enabled); - } - - public void setCheckedNum(int checkedNum) { - mCheckView.setCheckedNum(checkedNum); - } - - public void setChecked(boolean checked) { - mCheckView.setChecked(checked); - } - - private void setImage() { - if (mMedia.isGif()) { - SelectionSpec.getInstance().imageEngine.loadGifThumbnail(getContext(), mPreBindInfo.mResize, - mPreBindInfo.mPlaceholder, mThumbnail, mMedia.getContentUri()); - } else { - SelectionSpec.getInstance().imageEngine.loadThumbnail(getContext(), mPreBindInfo.mResize, - mPreBindInfo.mPlaceholder, mThumbnail, mMedia.getContentUri()); - } - } - - private void setVideoDuration() { - if (mMedia.isVideo()) { - mVideoDuration.setVisibility(VISIBLE); - mVideoDuration.setText(DateUtils.formatElapsedTime(mMedia.duration / 1000)); - } else { - mVideoDuration.setVisibility(GONE); - } - } - - public void setOnMediaGridClickListener(OnMediaGridClickListener listener) { - mListener = listener; - } - - public void removeOnMediaGridClickListener() { - mListener = null; - } - - public interface OnMediaGridClickListener { - - void onThumbnailClicked(ImageView thumbnail, Item item, RecyclerView.ViewHolder holder); - - void onCheckViewClicked(CheckView checkView, Item item, RecyclerView.ViewHolder holder); - } - - public static class PreBindInfo { - int mResize; - Drawable mPlaceholder; - boolean mCheckViewCountable; - RecyclerView.ViewHolder mViewHolder; - - public PreBindInfo(int resize, Drawable placeholder, boolean checkViewCountable, - RecyclerView.ViewHolder viewHolder) { - mResize = resize; - mPlaceholder = placeholder; - mCheckViewCountable = checkViewCountable; - mViewHolder = viewHolder; - } - } - -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/MediaGridInset.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/MediaGridInset.java deleted file mode 100644 index eebcd42..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/MediaGridInset.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui.widget; - -import android.graphics.Rect; -import android.support.v7.widget.RecyclerView; -import android.view.View; - -public class MediaGridInset extends RecyclerView.ItemDecoration { - - private int mSpanCount; - private int mSpacing; - private boolean mIncludeEdge; - - public MediaGridInset(int spanCount, int spacing, boolean includeEdge) { - this.mSpanCount = spanCount; - this.mSpacing = spacing; - this.mIncludeEdge = includeEdge; - } - - @Override - public void getItemOffsets(Rect outRect, View view, RecyclerView parent, - RecyclerView.State state) { - int position = parent.getChildAdapterPosition(view); // item position - int column = position % mSpanCount; // item column - - if (mIncludeEdge) { - // spacing - column * ((1f / spanCount) * spacing) - outRect.left = mSpacing - column * mSpacing / mSpanCount; - // (column + 1) * ((1f / spanCount) * spacing) - outRect.right = (column + 1) * mSpacing / mSpanCount; - - if (position < mSpanCount) { // top edge - outRect.top = mSpacing; - } - outRect.bottom = mSpacing; // item bottom - } else { - // column * ((1f / spanCount) * spacing) - outRect.left = column * mSpacing / mSpanCount; - // spacing - (column + 1) * ((1f / spanCount) * spacing) - outRect.right = mSpacing - (column + 1) * mSpacing / mSpanCount; - if (position >= mSpanCount) { - outRect.top = mSpacing; // item top - } - } - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/PreviewViewPager.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/PreviewViewPager.java deleted file mode 100644 index 56fd370..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/PreviewViewPager.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui.widget; - -import android.content.Context; -import android.support.v4.view.ViewPager; -import android.util.AttributeSet; -import android.view.View; - -import it.sephiroth.android.library.imagezoom.ImageViewTouch; - -public class PreviewViewPager extends ViewPager { - - public PreviewViewPager(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) { - if (v instanceof ImageViewTouch) { - return ((ImageViewTouch) v).canScroll(dx) || super.canScroll(v, checkV, dx, x, y); - } - return super.canScroll(v, checkV, dx, x, y); - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/RoundedRectangleImageView.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/RoundedRectangleImageView.java deleted file mode 100644 index 2855157..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/RoundedRectangleImageView.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui.widget; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Path; -import android.graphics.RectF; -import android.support.v7.widget.AppCompatImageView; -import android.util.AttributeSet; - -public class RoundedRectangleImageView extends AppCompatImageView { - - private float mRadius; // dp - private Path mRoundedRectPath; - private RectF mRectF; - - public RoundedRectangleImageView(Context context) { - super(context); - init(context); - } - - public RoundedRectangleImageView(Context context, AttributeSet attrs) { - super(context, attrs); - init(context); - } - - public RoundedRectangleImageView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - init(context); - } - - private void init(Context context) { - float density = context.getResources().getDisplayMetrics().density; - mRadius = 2.0f * density; - mRoundedRectPath = new Path(); - mRectF = new RectF(); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - mRectF.set(0.0f, 0.0f, getMeasuredWidth(), getMeasuredHeight()); - mRoundedRectPath.addRoundRect(mRectF, mRadius, mRadius, Path.Direction.CW); - } - - @Override - protected void onDraw(Canvas canvas) { - canvas.clipPath(mRoundedRectPath); - super.onDraw(canvas); - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/SquareFrameLayout.java b/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/SquareFrameLayout.java deleted file mode 100644 index 1f95518..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/ui/widget/SquareFrameLayout.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.ui.widget; - -import android.content.Context; -import android.util.AttributeSet; -import android.widget.FrameLayout; - -public class SquareFrameLayout extends FrameLayout { - - public SquareFrameLayout(Context context) { - super(context); - } - - public SquareFrameLayout(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, widthMeasureSpec); - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/utils/ExifInterfaceCompat.java b/matisse/src/main/java/com/zhihu/matisse/internal/utils/ExifInterfaceCompat.java deleted file mode 100644 index b2be0e4..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/utils/ExifInterfaceCompat.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.utils; - -import android.media.ExifInterface; -import android.text.TextUtils; -import android.util.Log; - -import java.io.IOException; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.TimeZone; - -/** - * Bug fixture for ExifInterface constructor. - */ -final class ExifInterfaceCompat { - private static final String TAG = ExifInterfaceCompat.class.getSimpleName(); - private static final int EXIF_DEGREE_FALLBACK_VALUE = -1; - - /** - * Do not instantiate this class. - */ - private ExifInterfaceCompat() { - } - - /** - * Creates new instance of {@link ExifInterface}. - * Original constructor won't check filename value, so if null value has been passed, - * the process will be killed because of SIGSEGV. - * Google Play crash report system cannot perceive this crash, so this method will throw - * {@link NullPointerException} when the filename is null. - * - * @param filename a JPEG filename. - * @return {@link ExifInterface} instance. - * @throws IOException something wrong with I/O. - */ - public static ExifInterface newInstance(String filename) throws IOException { - if (filename == null) throw new NullPointerException("filename should not be null"); - return new ExifInterface(filename); - } - - private static Date getExifDateTime(String filepath) { - ExifInterface exif; - try { - // ExifInterface does not check whether file path is null or not, - // so passing null file path argument to its constructor causing SIGSEGV. - // We should avoid such a situation by checking file path string. - exif = newInstance(filepath); - } catch (IOException ex) { - Log.e(TAG, "cannot read exif", ex); - return null; - } - - String date = exif.getAttribute(ExifInterface.TAG_DATETIME); - if (TextUtils.isEmpty(date)) { - return null; - } - try { - SimpleDateFormat formatter = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss"); - formatter.setTimeZone(TimeZone.getTimeZone("UTC")); - return formatter.parse(date); - } catch (ParseException e) { - Log.d(TAG, "failed to parse date taken", e); - } - return null; - } - - /** - * Read exif info and get datetime value of the photo. - * - * @param filepath to get datetime - * @return when a photo taken. - */ - public static long getExifDateTimeInMillis(String filepath) { - Date datetime = getExifDateTime(filepath); - if (datetime == null) { - return -1; - } - return datetime.getTime(); - } - - /** - * Read exif info and get orientation value of the photo. - * - * @param filepath to get exif. - * @return exif orientation value - */ - public static int getExifOrientation(String filepath) { - ExifInterface exif; - try { - // ExifInterface does not check whether file path is null or not, - // so passing null file path argument to its constructor causing SIGSEGV. - // We should avoid such a situation by checking file path string. - exif = newInstance(filepath); - } catch (IOException ex) { - Log.e(TAG, "cannot read exif", ex); - return EXIF_DEGREE_FALLBACK_VALUE; - } - - int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, EXIF_DEGREE_FALLBACK_VALUE); - if (orientation == EXIF_DEGREE_FALLBACK_VALUE) { - return 0; - } - // We only recognize a subset of orientation tag values. - switch (orientation) { - case ExifInterface.ORIENTATION_ROTATE_90: - return 90; - case ExifInterface.ORIENTATION_ROTATE_180: - return 180; - case ExifInterface.ORIENTATION_ROTATE_270: - return 270; - default: - return 0; - } - } -} \ No newline at end of file diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/utils/MediaStoreCompat.java b/matisse/src/main/java/com/zhihu/matisse/internal/utils/MediaStoreCompat.java deleted file mode 100644 index 54a10c9..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/utils/MediaStoreCompat.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.utils; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.net.Uri; -import android.os.Build; -import android.os.Environment; -import android.provider.MediaStore; -import android.support.v4.app.Fragment; -import android.support.v4.content.FileProvider; -import android.support.v4.os.EnvironmentCompat; - -import com.zhihu.matisse.internal.entity.CaptureStrategy; - -import java.io.File; -import java.io.IOException; -import java.lang.ref.WeakReference; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.List; -import java.util.Locale; - -public class MediaStoreCompat { - - private final WeakReference mContext; - private final WeakReference mFragment; - private CaptureStrategy mCaptureStrategy; - private Uri mCurrentPhotoUri; - private String mCurrentPhotoPath; - - public MediaStoreCompat(Activity activity) { - mContext = new WeakReference<>(activity); - mFragment = null; - } - - public MediaStoreCompat(Activity activity, Fragment fragment) { - mContext = new WeakReference<>(activity); - mFragment = new WeakReference<>(fragment); - } - - /** - * Checks whether the device has a camera feature or not. - * - * @param context a context to check for camera feature. - * @return true if the device has a camera feature. false otherwise. - */ - public static boolean hasCameraFeature(Context context) { - PackageManager pm = context.getApplicationContext().getPackageManager(); - return pm.hasSystemFeature(PackageManager.FEATURE_CAMERA); - } - - public void setCaptureStrategy(CaptureStrategy strategy) { - mCaptureStrategy = strategy; - } - - public void dispatchCaptureIntent(Context context, int requestCode) { - Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); - if (captureIntent.resolveActivity(context.getPackageManager()) != null) { - File photoFile = null; - try { - photoFile = createImageFile(); - } catch (IOException e) { - e.printStackTrace(); - } - - if (photoFile != null) { - mCurrentPhotoPath = photoFile.getAbsolutePath(); - mCurrentPhotoUri = FileProvider.getUriForFile(mContext.get(), - mCaptureStrategy.authority, photoFile); - captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, mCurrentPhotoUri); - captureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - List resInfoList = context.getPackageManager() - .queryIntentActivities(captureIntent, PackageManager.MATCH_DEFAULT_ONLY); - for (ResolveInfo resolveInfo : resInfoList) { - String packageName = resolveInfo.activityInfo.packageName; - context.grantUriPermission(packageName, mCurrentPhotoUri, - Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION); - } - } - if (mFragment != null) { - mFragment.get().startActivityForResult(captureIntent, requestCode); - } else { - mContext.get().startActivityForResult(captureIntent, requestCode); - } - } - } - } - - @SuppressWarnings("ResultOfMethodCallIgnored") - private File createImageFile() throws IOException { - // Create an image file name - String timeStamp = - new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date()); - String imageFileName = String.format("JPEG_%s.jpg", timeStamp); - File storageDir; - if (mCaptureStrategy.isPublic) { - storageDir = Environment.getExternalStoragePublicDirectory( - Environment.DIRECTORY_PICTURES); - if (!storageDir.exists()) storageDir.mkdirs(); - } else { - storageDir = mContext.get().getExternalFilesDir(Environment.DIRECTORY_PICTURES); - } - if (mCaptureStrategy.directory != null) { - storageDir = new File(storageDir, mCaptureStrategy.directory); - if (!storageDir.exists()) storageDir.mkdirs(); - } - - // Avoid joining path components manually - File tempFile = new File(storageDir, imageFileName); - - // Handle the situation that user's external storage is not ready - if (!Environment.MEDIA_MOUNTED.equals(EnvironmentCompat.getStorageState(tempFile))) { - return null; - } - - return tempFile; - } - - public Uri getCurrentPhotoUri() { - return mCurrentPhotoUri; - } - - public String getCurrentPhotoPath() { - return mCurrentPhotoPath; - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/utils/PathUtils.java b/matisse/src/main/java/com/zhihu/matisse/internal/utils/PathUtils.java deleted file mode 100644 index de64322..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/utils/PathUtils.java +++ /dev/null @@ -1,135 +0,0 @@ -package com.zhihu.matisse.internal.utils; - -import android.annotation.TargetApi; -import android.content.ContentUris; -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; -import android.os.Build; -import android.os.Environment; -import android.provider.DocumentsContract; -import android.provider.MediaStore; - -/** - * http://stackoverflow.com/a/27271131/4739220 - */ - -public class PathUtils { - /** - * Get a file path from a Uri. This will get the the path for Storage Access - * Framework Documents, as well as the _data field for the MediaStore and - * other file-based ContentProviders. - * - * @param context The context. - * @param uri The Uri to query. - * @author paulburke - */ - @TargetApi(Build.VERSION_CODES.KITKAT) - public static String getPath(final Context context, final Uri uri) { - // DocumentProvider - if (Platform.hasKitKat() && DocumentsContract.isDocumentUri(context, uri)) { - // ExternalStorageProvider - if (isExternalStorageDocument(uri)) { - final String docId = DocumentsContract.getDocumentId(uri); - final String[] split = docId.split(":"); - final String type = split[0]; - - if ("primary".equalsIgnoreCase(type)) { - return Environment.getExternalStorageDirectory() + "/" + split[1]; - } - - // TODO handle non-primary volumes - } else if (isDownloadsDocument(uri)) { // DownloadsProvider - - final String id = DocumentsContract.getDocumentId(uri); - final Uri contentUri = ContentUris.withAppendedId( - Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); - - return getDataColumn(context, contentUri, null, null); - } else if (isMediaDocument(uri)) { // MediaProvider - final String docId = DocumentsContract.getDocumentId(uri); - final String[] split = docId.split(":"); - final String type = split[0]; - - Uri contentUri = null; - if ("image".equals(type)) { - contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; - } else if ("video".equals(type)) { - contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; - } else if ("audio".equals(type)) { - contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; - } - - final String selection = "_id=?"; - final String[] selectionArgs = new String[]{ - split[1] - }; - - return getDataColumn(context, contentUri, selection, selectionArgs); - } - } else if ("content".equalsIgnoreCase(uri.getScheme())) { // MediaStore (and general) - return getDataColumn(context, uri, null, null); - } else if ("file".equalsIgnoreCase(uri.getScheme())) { // File - return uri.getPath(); - } - - return null; - } - - /** - * Get the value of the data column for this Uri. This is useful for - * MediaStore Uris, and other file-based ContentProviders. - * - * @param context The context. - * @param uri The Uri to query. - * @param selection (Optional) Filter used in the query. - * @param selectionArgs (Optional) Selection arguments used in the query. - * @return The value of the _data column, which is typically a file path. - */ - public static String getDataColumn(Context context, Uri uri, String selection, - String[] selectionArgs) { - - Cursor cursor = null; - final String column = "_data"; - final String[] projection = { - column - }; - - try { - cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null); - if (cursor != null && cursor.moveToFirst()) { - final int columnIndex = cursor.getColumnIndexOrThrow(column); - return cursor.getString(columnIndex); - } - } finally { - if (cursor != null) - cursor.close(); - } - return null; - } - - - /** - * @param uri The Uri to check. - * @return Whether the Uri authority is ExternalStorageProvider. - */ - public static boolean isExternalStorageDocument(Uri uri) { - return "com.android.externalstorage.documents".equals(uri.getAuthority()); - } - - /** - * @param uri The Uri to check. - * @return Whether the Uri authority is DownloadsProvider. - */ - public static boolean isDownloadsDocument(Uri uri) { - return "com.android.providers.downloads.documents".equals(uri.getAuthority()); - } - - /** - * @param uri The Uri to check. - * @return Whether the Uri authority is MediaProvider. - */ - public static boolean isMediaDocument(Uri uri) { - return "com.android.providers.media.documents".equals(uri.getAuthority()); - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/utils/PhotoMetadataUtils.java b/matisse/src/main/java/com/zhihu/matisse/internal/utils/PhotoMetadataUtils.java deleted file mode 100644 index 59c1c8c..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/utils/PhotoMetadataUtils.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (C) 2014 nohana, Inc. - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.utils; - -import android.app.Activity; -import android.content.ContentResolver; -import android.content.Context; -import android.database.Cursor; -import android.graphics.BitmapFactory; -import android.graphics.Point; -import android.media.ExifInterface; -import android.net.Uri; -import android.provider.MediaStore; -import android.util.DisplayMetrics; -import android.util.Log; - -import com.zhihu.matisse.MimeType; -import com.zhihu.matisse.R; -import com.zhihu.matisse.filter.Filter; -import com.zhihu.matisse.internal.entity.Item; -import com.zhihu.matisse.internal.entity.SelectionSpec; -import com.zhihu.matisse.internal.entity.IncapableCause; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.text.DecimalFormat; -import java.text.NumberFormat; -import java.util.Locale; - -public final class PhotoMetadataUtils { - private static final String TAG = PhotoMetadataUtils.class.getSimpleName(); - private static final int MAX_WIDTH = 1600; - private static final String SCHEME_CONTENT = "content"; - - private PhotoMetadataUtils() { - throw new AssertionError("oops! the utility class is about to be instantiated..."); - } - - public static int getPixelsCount(ContentResolver resolver, Uri uri) { - Point size = getBitmapBound(resolver, uri); - return size.x * size.y; - } - - public static Point getBitmapSize(Uri uri, Activity activity) { - ContentResolver resolver = activity.getContentResolver(); - Point imageSize = getBitmapBound(resolver, uri); - int w = imageSize.x; - int h = imageSize.y; - if (PhotoMetadataUtils.shouldRotate(resolver, uri)) { - w = imageSize.y; - h = imageSize.x; - } - if (h == 0) return new Point(MAX_WIDTH, MAX_WIDTH); - DisplayMetrics metrics = new DisplayMetrics(); - activity.getWindowManager().getDefaultDisplay().getMetrics(metrics); - float screenWidth = (float) metrics.widthPixels; - float screenHeight = (float) metrics.heightPixels; - float widthScale = screenWidth / w; - float heightScale = screenHeight / h; - if (widthScale > heightScale) { - return new Point((int) (w * widthScale), (int) (h * heightScale)); - } - return new Point((int) (w * widthScale), (int) (h * heightScale)); - } - - public static Point getBitmapBound(ContentResolver resolver, Uri uri) { - InputStream is = null; - try { - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inJustDecodeBounds = true; - is = resolver.openInputStream(uri); - BitmapFactory.decodeStream(is, null, options); - int width = options.outWidth; - int height = options.outHeight; - return new Point(width, height); - } catch (FileNotFoundException e) { - return new Point(0, 0); - } finally { - if (is != null) { - try { - is.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - } - - public static String getPath(ContentResolver resolver, Uri uri) { - if (uri == null) { - return null; - } - - if (SCHEME_CONTENT.equals(uri.getScheme())) { - Cursor cursor = null; - try { - cursor = resolver.query(uri, new String[]{MediaStore.Images.ImageColumns.DATA}, - null, null, null); - if (cursor == null || !cursor.moveToFirst()) { - return null; - } - return cursor.getString(cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA)); - } finally { - if (cursor != null) { - cursor.close(); - } - } - } - return uri.getPath(); - } - - public static IncapableCause isAcceptable(Context context, Item item) { - if (!isSelectableType(context, item)) { - return new IncapableCause(context.getString(R.string.error_file_type)); - } - - if (SelectionSpec.getInstance().filters != null) { - for (Filter filter : SelectionSpec.getInstance().filters) { - IncapableCause incapableCause = filter.filter(context, item); - if (incapableCause != null) { - return incapableCause; - } - } - } - return null; - } - - private static boolean isSelectableType(Context context, Item item) { - if (context == null) { - return false; - } - - ContentResolver resolver = context.getContentResolver(); - for (MimeType type : SelectionSpec.getInstance().mimeTypeSet) { - if (type.checkType(resolver, item.getContentUri())) { - return true; - } - } - return false; - } - - private static boolean shouldRotate(ContentResolver resolver, Uri uri) { - ExifInterface exif; - try { - exif = ExifInterfaceCompat.newInstance(getPath(resolver, uri)); - } catch (IOException e) { - Log.e(TAG, "could not read exif info of the image: " + uri); - return false; - } - int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1); - return orientation == ExifInterface.ORIENTATION_ROTATE_90 - || orientation == ExifInterface.ORIENTATION_ROTATE_270; - } - - public static float getSizeInMB(long sizeInBytes) { - DecimalFormat df = (DecimalFormat) NumberFormat.getNumberInstance(Locale.US); - df.applyPattern("0.0"); - String result = df.format((float) sizeInBytes / 1024 / 1024); - Log.e(TAG, "getSizeInMB: " + result); - result = result.replaceAll(",", "."); // in some case , 0.0 will be 0,0 - return Float.valueOf(result); - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/utils/Platform.java b/matisse/src/main/java/com/zhihu/matisse/internal/utils/Platform.java deleted file mode 100644 index df41989..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/utils/Platform.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.zhihu.matisse.internal.utils; - -import android.os.Build; - -/** - * @author JoongWon Baik - */ -public class Platform { - public static boolean hasICS() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH; - } - - public static boolean hasKitKat() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; - } -} diff --git a/matisse/src/main/java/com/zhihu/matisse/internal/utils/UIUtils.java b/matisse/src/main/java/com/zhihu/matisse/internal/utils/UIUtils.java deleted file mode 100644 index 129b599..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/internal/utils/UIUtils.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.internal.utils; - -import android.content.Context; - -public class UIUtils { - - public static int spanCount(Context context, int gridExpectedSize) { - int screenWidth = context.getResources().getDisplayMetrics().widthPixels; - float expected = (float) screenWidth / (float) gridExpectedSize; - int spanCount = Math.round(expected); - if (spanCount == 0) { - spanCount = 1; - } - return spanCount; - } - -} diff --git a/matisse/src/main/java/com/zhihu/matisse/listener/OnCheckedListener.java b/matisse/src/main/java/com/zhihu/matisse/listener/OnCheckedListener.java deleted file mode 100644 index 4a0ebae..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/listener/OnCheckedListener.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.zhihu.matisse.listener; - - -/** - * when original is enabled , callback immediately when user check or uncheck original. - */ -public interface OnCheckedListener { - void onCheck(boolean isChecked); -} diff --git a/matisse/src/main/java/com/zhihu/matisse/listener/OnFragmentInteractionListener.java b/matisse/src/main/java/com/zhihu/matisse/listener/OnFragmentInteractionListener.java deleted file mode 100644 index 79f5536..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/listener/OnFragmentInteractionListener.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.zhihu.matisse.listener; - -/** - * PreViewItemFragment 和 BasePreViewActivity 通信的接口 ,为了方便拿到 ImageViewTouch 的点击事件 - */ -public interface OnFragmentInteractionListener { - /** - * ImageViewTouch 被点击了 - */ - void onClick(); -} diff --git a/matisse/src/main/java/com/zhihu/matisse/listener/OnSelectedListener.java b/matisse/src/main/java/com/zhihu/matisse/listener/OnSelectedListener.java deleted file mode 100644 index 33e374e..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/listener/OnSelectedListener.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.zhihu.matisse.listener; - -import android.net.Uri; -import android.support.annotation.NonNull; - -import java.util.List; - -public interface OnSelectedListener { - /** - * @param uriList the selected item {@link Uri} list. - * @param pathList the selected item file path list. - */ - void onSelected(@NonNull List uriList, @NonNull List pathList); -} diff --git a/matisse/src/main/java/com/zhihu/matisse/ui/MatisseActivity.java b/matisse/src/main/java/com/zhihu/matisse/ui/MatisseActivity.java deleted file mode 100644 index 0f0322c..0000000 --- a/matisse/src/main/java/com/zhihu/matisse/ui/MatisseActivity.java +++ /dev/null @@ -1,428 +0,0 @@ -/* - * Copyright 2017 Zhihu Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.zhihu.matisse.ui; - -import android.app.Activity; -import android.content.Intent; -import android.content.res.TypedArray; -import android.database.Cursor; -import android.graphics.PorterDuff; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; -import android.view.MenuItem; -import android.view.View; -import android.widget.AdapterView; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.zhihu.matisse.R; -import com.zhihu.matisse.internal.entity.Album; -import com.zhihu.matisse.internal.entity.Item; -import com.zhihu.matisse.internal.entity.SelectionSpec; -import com.zhihu.matisse.internal.model.AlbumCollection; -import com.zhihu.matisse.internal.model.SelectedItemCollection; -import com.zhihu.matisse.internal.ui.AlbumPreviewActivity; -import com.zhihu.matisse.internal.ui.BasePreviewActivity; -import com.zhihu.matisse.internal.ui.MediaSelectionFragment; -import com.zhihu.matisse.internal.ui.SelectedPreviewActivity; -import com.zhihu.matisse.internal.ui.adapter.AlbumMediaAdapter; -import com.zhihu.matisse.internal.ui.adapter.AlbumsAdapter; -import com.zhihu.matisse.internal.ui.widget.AlbumsSpinner; -import com.zhihu.matisse.internal.ui.widget.CheckRadioView; -import com.zhihu.matisse.internal.ui.widget.IncapableDialog; -import com.zhihu.matisse.internal.utils.MediaStoreCompat; -import com.zhihu.matisse.internal.utils.PathUtils; -import com.zhihu.matisse.internal.utils.PhotoMetadataUtils; - -import java.util.ArrayList; - -/** - * Main Activity to display albums and media content (images/videos) in each album - * and also support media selecting operations. - */ -public class MatisseActivity extends AppCompatActivity implements - AlbumCollection.AlbumCallbacks, AdapterView.OnItemSelectedListener, - MediaSelectionFragment.SelectionProvider, View.OnClickListener, - AlbumMediaAdapter.CheckStateListener, AlbumMediaAdapter.OnMediaClickListener, - AlbumMediaAdapter.OnPhotoCapture { - - public static final String EXTRA_RESULT_SELECTION = "extra_result_selection"; - public static final String EXTRA_RESULT_SELECTION_PATH = "extra_result_selection_path"; - public static final String EXTRA_RESULT_ORIGINAL_ENABLE = "extra_result_original_enable"; - private static final int REQUEST_CODE_PREVIEW = 23; - private static final int REQUEST_CODE_CAPTURE = 24; - public static final String CHECK_STATE = "checkState"; - private final AlbumCollection mAlbumCollection = new AlbumCollection(); - private MediaStoreCompat mMediaStoreCompat; - private SelectedItemCollection mSelectedCollection = new SelectedItemCollection(this); - private SelectionSpec mSpec; - - private AlbumsSpinner mAlbumsSpinner; - private AlbumsAdapter mAlbumsAdapter; - private TextView mButtonPreview; - private TextView mButtonApply; - private View mContainer; - private View mEmptyView; - - private LinearLayout mOriginalLayout; - private CheckRadioView mOriginal; - private boolean mOriginalEnable; - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - // programmatically set theme before super.onCreate() - mSpec = SelectionSpec.getInstance(); - setTheme(mSpec.themeId); - super.onCreate(savedInstanceState); - if (!mSpec.hasInited) { - setResult(RESULT_CANCELED); - finish(); - return; - } - setContentView(R.layout.activity_matisse); - - if (mSpec.needOrientationRestriction()) { - setRequestedOrientation(mSpec.orientation); - } - - if (mSpec.capture) { - mMediaStoreCompat = new MediaStoreCompat(this); - if (mSpec.captureStrategy == null) - throw new RuntimeException("Don't forget to set CaptureStrategy."); - mMediaStoreCompat.setCaptureStrategy(mSpec.captureStrategy); - } - - Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - ActionBar actionBar = getSupportActionBar(); - actionBar.setDisplayShowTitleEnabled(false); - actionBar.setDisplayHomeAsUpEnabled(true); - Drawable navigationIcon = toolbar.getNavigationIcon(); - TypedArray ta = getTheme().obtainStyledAttributes(new int[]{R.attr.album_element_color}); - int color = ta.getColor(0, 0); - ta.recycle(); - navigationIcon.setColorFilter(color, PorterDuff.Mode.SRC_IN); - - mButtonPreview = (TextView) findViewById(R.id.button_preview); - mButtonApply = (TextView) findViewById(R.id.button_apply); - mButtonPreview.setOnClickListener(this); - mButtonApply.setOnClickListener(this); - mContainer = findViewById(R.id.container); - mEmptyView = findViewById(R.id.empty_view); - mOriginalLayout = findViewById(R.id.originalLayout); - mOriginal = findViewById(R.id.original); - mOriginalLayout.setOnClickListener(this); - - mSelectedCollection.onCreate(savedInstanceState); - if (savedInstanceState != null) { - mOriginalEnable = savedInstanceState.getBoolean(CHECK_STATE); - } - updateBottomToolbar(); - - mAlbumsAdapter = new AlbumsAdapter(this, null, false); - mAlbumsSpinner = new AlbumsSpinner(this); - mAlbumsSpinner.setOnItemSelectedListener(this); - mAlbumsSpinner.setSelectedTextView((TextView) findViewById(R.id.selected_album)); - mAlbumsSpinner.setPopupAnchorView(findViewById(R.id.toolbar)); - mAlbumsSpinner.setAdapter(mAlbumsAdapter); - mAlbumCollection.onCreate(this, this); - mAlbumCollection.onRestoreInstanceState(savedInstanceState); - mAlbumCollection.loadAlbums(); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - mSelectedCollection.onSaveInstanceState(outState); - mAlbumCollection.onSaveInstanceState(outState); - outState.putBoolean("checkState", mOriginalEnable); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - mAlbumCollection.onDestroy(); - mSpec.onCheckedListener = null; - mSpec.onSelectedListener = null; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == android.R.id.home) { - onBackPressed(); - return true; - } - return super.onOptionsItemSelected(item); - } - - @Override - public void onBackPressed() { - setResult(Activity.RESULT_CANCELED); - super.onBackPressed(); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (resultCode != RESULT_OK) - return; - - if (requestCode == REQUEST_CODE_PREVIEW) { - Bundle resultBundle = data.getBundleExtra(BasePreviewActivity.EXTRA_RESULT_BUNDLE); - ArrayList selected = resultBundle.getParcelableArrayList(SelectedItemCollection.STATE_SELECTION); - mOriginalEnable = data.getBooleanExtra(BasePreviewActivity.EXTRA_RESULT_ORIGINAL_ENABLE, false); - int collectionType = resultBundle.getInt(SelectedItemCollection.STATE_COLLECTION_TYPE, - SelectedItemCollection.COLLECTION_UNDEFINED); - if (data.getBooleanExtra(BasePreviewActivity.EXTRA_RESULT_APPLY, false)) { - Intent result = new Intent(); - ArrayList selectedUris = new ArrayList<>(); - ArrayList selectedPaths = new ArrayList<>(); - if (selected != null) { - for (Item item : selected) { - selectedUris.add(item.getContentUri()); - selectedPaths.add(PathUtils.getPath(this, item.getContentUri())); - } - } - result.putParcelableArrayListExtra(EXTRA_RESULT_SELECTION, selectedUris); - result.putStringArrayListExtra(EXTRA_RESULT_SELECTION_PATH, selectedPaths); - result.putExtra(EXTRA_RESULT_ORIGINAL_ENABLE, mOriginalEnable); - setResult(RESULT_OK, result); - finish(); - } else { - mSelectedCollection.overwrite(selected, collectionType); - Fragment mediaSelectionFragment = getSupportFragmentManager().findFragmentByTag( - MediaSelectionFragment.class.getSimpleName()); - if (mediaSelectionFragment instanceof MediaSelectionFragment) { - ((MediaSelectionFragment) mediaSelectionFragment).refreshMediaGrid(); - } - updateBottomToolbar(); - } - } else if (requestCode == REQUEST_CODE_CAPTURE) { - // Just pass the data back to previous calling Activity. - Uri contentUri = mMediaStoreCompat.getCurrentPhotoUri(); - String path = mMediaStoreCompat.getCurrentPhotoPath(); - ArrayList selected = new ArrayList<>(); - selected.add(contentUri); - ArrayList selectedPath = new ArrayList<>(); - selectedPath.add(path); - Intent result = new Intent(); - result.putParcelableArrayListExtra(EXTRA_RESULT_SELECTION, selected); - result.putStringArrayListExtra(EXTRA_RESULT_SELECTION_PATH, selectedPath); - setResult(RESULT_OK, result); - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) - MatisseActivity.this.revokeUriPermission(contentUri, - Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION); - finish(); - } - } - - private void updateBottomToolbar() { - - int selectedCount = mSelectedCollection.count(); - if (selectedCount == 0) { - mButtonPreview.setEnabled(false); - mButtonApply.setEnabled(false); - mButtonApply.setText(getString(R.string.button_sure_default)); - } else if (selectedCount == 1 && mSpec.singleSelectionModeEnabled()) { - mButtonPreview.setEnabled(true); - mButtonApply.setText(R.string.button_sure_default); - mButtonApply.setEnabled(true); - } else { - mButtonPreview.setEnabled(true); - mButtonApply.setEnabled(true); - mButtonApply.setText(getString(R.string.button_sure, selectedCount)); - } - - - if (mSpec.originalable) { - mOriginalLayout.setVisibility(View.VISIBLE); - updateOriginalState(); - } else { - mOriginalLayout.setVisibility(View.INVISIBLE); - } - - - } - - - private void updateOriginalState() { - mOriginal.setChecked(mOriginalEnable); - if (countOverMaxSize() > 0) { - - if (mOriginalEnable) { - IncapableDialog incapableDialog = IncapableDialog.newInstance("", - getString(R.string.error_over_original_size, mSpec.originalMaxSize)); - incapableDialog.show(getSupportFragmentManager(), - IncapableDialog.class.getName()); - - mOriginal.setChecked(false); - mOriginalEnable = false; - } - } - } - - - private int countOverMaxSize() { - int count = 0; - int selectedCount = mSelectedCollection.count(); - for (int i = 0; i < selectedCount; i++) { - Item item = mSelectedCollection.asList().get(i); - - if (item.isImage()) { - float size = PhotoMetadataUtils.getSizeInMB(item.size); - if (size > mSpec.originalMaxSize) { - count++; - } - } - } - return count; - } - - @Override - public void onClick(View v) { - if (v.getId() == R.id.button_preview) { - Intent intent = new Intent(this, SelectedPreviewActivity.class); - intent.putExtra(BasePreviewActivity.EXTRA_DEFAULT_BUNDLE, mSelectedCollection.getDataWithBundle()); - intent.putExtra(BasePreviewActivity.EXTRA_RESULT_ORIGINAL_ENABLE, mOriginalEnable); - startActivityForResult(intent, REQUEST_CODE_PREVIEW); - } else if (v.getId() == R.id.button_apply) { - Intent result = new Intent(); - ArrayList selectedUris = (ArrayList) mSelectedCollection.asListOfUri(); - result.putParcelableArrayListExtra(EXTRA_RESULT_SELECTION, selectedUris); - ArrayList selectedPaths = (ArrayList) mSelectedCollection.asListOfString(); - result.putStringArrayListExtra(EXTRA_RESULT_SELECTION_PATH, selectedPaths); - result.putExtra(EXTRA_RESULT_ORIGINAL_ENABLE, mOriginalEnable); - setResult(RESULT_OK, result); - finish(); - } else if (v.getId() == R.id.originalLayout) { - int count = countOverMaxSize(); - if (count > 0) { - IncapableDialog incapableDialog = IncapableDialog.newInstance("", - getString(R.string.error_over_original_count, count, mSpec.originalMaxSize)); - incapableDialog.show(getSupportFragmentManager(), - IncapableDialog.class.getName()); - return; - } - - mOriginalEnable = !mOriginalEnable; - mOriginal.setChecked(mOriginalEnable); - - if (mSpec.onCheckedListener != null) { - mSpec.onCheckedListener.onCheck(mOriginalEnable); - } - } - } - - @Override - public void onItemSelected(AdapterView parent, View view, int position, long id) { - mAlbumCollection.setStateCurrentSelection(position); - mAlbumsAdapter.getCursor().moveToPosition(position); - Album album = Album.valueOf(mAlbumsAdapter.getCursor()); - if (album.isAll() && SelectionSpec.getInstance().capture) { - album.addCaptureCount(); - } - onAlbumSelected(album); - } - - @Override - public void onNothingSelected(AdapterView parent) { - - } - - @Override - public void onAlbumLoad(final Cursor cursor) { - mAlbumsAdapter.swapCursor(cursor); - // select default album. - Handler handler = new Handler(Looper.getMainLooper()); - handler.post(new Runnable() { - - @Override - public void run() { - cursor.moveToPosition(mAlbumCollection.getCurrentSelection()); - mAlbumsSpinner.setSelection(MatisseActivity.this, - mAlbumCollection.getCurrentSelection()); - Album album = Album.valueOf(cursor); - if (album.isAll() && SelectionSpec.getInstance().capture) { - album.addCaptureCount(); - } - onAlbumSelected(album); - } - }); - } - - @Override - public void onAlbumReset() { - mAlbumsAdapter.swapCursor(null); - } - - private void onAlbumSelected(Album album) { - if (album.isAll() && album.isEmpty()) { - mContainer.setVisibility(View.GONE); - mEmptyView.setVisibility(View.VISIBLE); - } else { - mContainer.setVisibility(View.VISIBLE); - mEmptyView.setVisibility(View.GONE); - Fragment fragment = MediaSelectionFragment.newInstance(album); - getSupportFragmentManager() - .beginTransaction() - .replace(R.id.container, fragment, MediaSelectionFragment.class.getSimpleName()) - .commitAllowingStateLoss(); - } - } - - @Override - public void onUpdate() { - // notify bottom toolbar that check state changed. - updateBottomToolbar(); - - if (mSpec.onSelectedListener != null) { - mSpec.onSelectedListener.onSelected( - mSelectedCollection.asListOfUri(), mSelectedCollection.asListOfString()); - } - } - - @Override - public void onMediaClick(Album album, Item item, int adapterPosition) { - Intent intent = new Intent(this, AlbumPreviewActivity.class); - intent.putExtra(AlbumPreviewActivity.EXTRA_ALBUM, album); - intent.putExtra(AlbumPreviewActivity.EXTRA_ITEM, item); - intent.putExtra(BasePreviewActivity.EXTRA_DEFAULT_BUNDLE, mSelectedCollection.getDataWithBundle()); - intent.putExtra(BasePreviewActivity.EXTRA_RESULT_ORIGINAL_ENABLE, mOriginalEnable); - startActivityForResult(intent, REQUEST_CODE_PREVIEW); - } - - @Override - public SelectedItemCollection provideSelectedItemCollection() { - return mSelectedCollection; - } - - @Override - public void capture() { - if (mMediaStoreCompat != null) { - mMediaStoreCompat.dispatchCaptureIntent(this, REQUEST_CODE_CAPTURE); - } - } - -} diff --git a/matisse/src/main/res/color/dracula_bottom_toolbar_apply.xml b/matisse/src/main/res/color/dracula_bottom_toolbar_apply.xml deleted file mode 100644 index 84e13af..0000000 --- a/matisse/src/main/res/color/dracula_bottom_toolbar_apply.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/matisse/src/main/res/color/dracula_bottom_toolbar_preview.xml b/matisse/src/main/res/color/dracula_bottom_toolbar_preview.xml deleted file mode 100644 index 56e04b7..0000000 --- a/matisse/src/main/res/color/dracula_bottom_toolbar_preview.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/matisse/src/main/res/color/dracula_preview_bottom_toolbar_apply.xml b/matisse/src/main/res/color/dracula_preview_bottom_toolbar_apply.xml deleted file mode 100644 index 9920c27..0000000 --- a/matisse/src/main/res/color/dracula_preview_bottom_toolbar_apply.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/matisse/src/main/res/color/zhihu_bottom_toolbar_apply.xml b/matisse/src/main/res/color/zhihu_bottom_toolbar_apply.xml deleted file mode 100644 index d12c968..0000000 --- a/matisse/src/main/res/color/zhihu_bottom_toolbar_apply.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/matisse/src/main/res/color/zhihu_bottom_toolbar_preview.xml b/matisse/src/main/res/color/zhihu_bottom_toolbar_preview.xml deleted file mode 100644 index fef8d16..0000000 --- a/matisse/src/main/res/color/zhihu_bottom_toolbar_preview.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/matisse/src/main/res/color/zhihu_preview_bottom_toolbar_apply.xml b/matisse/src/main/res/color/zhihu_preview_bottom_toolbar_apply.xml deleted file mode 100644 index 0bec454..0000000 --- a/matisse/src/main/res/color/zhihu_preview_bottom_toolbar_apply.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - diff --git a/matisse/src/main/res/drawable-hdpi/ic_arrow_drop_down_white_24dp.png b/matisse/src/main/res/drawable-hdpi/ic_arrow_drop_down_white_24dp.png deleted file mode 100644 index 4c6076df77463404d7163c9929bad5798576c49b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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 diff --git a/matisse/src/main/res/drawable-hdpi/ic_empty_dracula.png b/matisse/src/main/res/drawable-hdpi/ic_empty_dracula.png deleted file mode 100644 index 0920df470690bbbc7b20e2f8b3cc11d05d52c3fc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5911 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 diff --git a/matisse/src/main/res/drawable-hdpi/ic_empty_zhihu.png b/matisse/src/main/res/drawable-hdpi/ic_empty_zhihu.png deleted file mode 100644 index 86ffe1cda6b9b98d715e1f670a2f99aeed337070..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5785 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 diff --git a/matisse/src/main/res/drawable-hdpi/ic_gif.png b/matisse/src/main/res/drawable-hdpi/ic_gif.png deleted file mode 100644 index d4085f56fb084eba0112bb70017881ba618fa333..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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 diff --git a/matisse/src/main/res/drawable-hdpi/ic_play_circle_outline_white_48dp.png b/matisse/src/main/res/drawable-hdpi/ic_play_circle_outline_white_48dp.png deleted file mode 100644 index 6e1b578c54d13ceabffc2d6f49a383bc73605988..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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 diff --git a/matisse/src/main/res/drawable-hdpi/ic_preview_radio_off.webp b/matisse/src/main/res/drawable-hdpi/ic_preview_radio_off.webp deleted file mode 100644 index 80930b9a3851cd44287fc37cd9a93d090d5cde81..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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 diff --git a/matisse/src/main/res/drawable-mdpi/ic_check_white_18dp.png b/matisse/src/main/res/drawable-mdpi/ic_check_white_18dp.png deleted file mode 100644 index ad1484767f791343581dfcdd35cfca4d0962c280..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 146 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 P2`4eoG0`s9d>Z{9WSgOK diff --git a/matisse/src/main/res/drawable-mdpi/ic_empty_zhihu.png b/matisse/src/main/res/drawable-mdpi/ic_empty_zhihu.png deleted file mode 100644 index f5628eee45059291eb92e29053378c59fb391fb0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3843 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 E1Fvf!WdHyG diff --git a/matisse/src/main/res/drawable-mdpi/ic_gif.png b/matisse/src/main/res/drawable-mdpi/ic_gif.png deleted file mode 100644 index aeeb0d4353897d4728aa9489bbb8c53ad005c98f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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 diff --git a/matisse/src/main/res/drawable-mdpi/ic_play_circle_outline_white_48dp.png b/matisse/src/main/res/drawable-mdpi/ic_play_circle_outline_white_48dp.png deleted file mode 100644 index 615b80d08543f8285c7ac5ffd66435bf0da1b7ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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 diff --git a/matisse/src/main/res/drawable-mdpi/ic_preview_radio_off.webp b/matisse/src/main/res/drawable-mdpi/ic_preview_radio_off.webp deleted file mode 100644 index 1a8f6c181bd65a6bf17999e7e8310f9e4fcc1367..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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 diff --git a/matisse/src/main/res/drawable-mdpi/ic_preview_radio_on.webp b/matisse/src/main/res/drawable-mdpi/ic_preview_radio_on.webp deleted file mode 100644 index b336c9c6ea2b9d952c9516bd8c580ca0feed8c41..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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 diff --git a/matisse/src/main/res/drawable-xhdpi/ic_arrow_drop_down_white_24dp.png b/matisse/src/main/res/drawable-xhdpi/ic_arrow_drop_down_white_24dp.png deleted file mode 100644 index da239e4f4e0169d670679e8af8c86c5c4fffa7ca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 120 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 S42-GR13pM9NR*2i1^y4^lequ@ diff --git a/matisse/src/main/res/drawable-xhdpi/ic_empty_zhihu.png b/matisse/src/main/res/drawable-xhdpi/ic_empty_zhihu.png deleted file mode 100644 index c223b5691fede910722565a39c0ad54f5837da53..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7977 zcmeHsRa9Hww{FNUl#~`L*5XjCK?}tx1S!(u?oyx>3GN!CMT)ya3l#SfG*Da{C=Nl2 zI}|7A$#0DRdAtwzj{9&P&K_fry&mTL*7wc5*IaY%6``ggPk>K_4*&oN6cuDO0010@ ze{b*u002N1QVGXCa9lOyr2&;Fnr#4pZdFlMO3MppKijvQM%Ta3`rMt~*?!YpAww9{ zFCaV}vHB;W_v=FvuB76mlu}3>LgPj7*thQ*EOVu!2A|pt$sxZfBINU0GZ26Ah{++z zDa8mIM+-3&tlAL{3JV1&t~u>r&n$@C-k$sHA$_e;!w0B6)T(P`f%#($5 zS5%fW4G_ctzyU)6Kw>!He~16`;$X$_C*^B`e(~!3ywR;U&wNb=u3j?<3#h!BbuA)B%%4 zVF~kwY0!e#BCv$n9L+gE_;PUd>L}44``)PWA`1S0qtk3=+nJt|)gM;FQvU>Juyobx zwa=>6WMkHhmEHu`Zq5n?=Pq5R1eh!h3um^eApo|_#=^N1nbU*tm9YA&T}!AywJHFd z!RD}PA|Ng+Ho!AYS_D9SHaNg)L1qRo2uKQrhfJG(Oi|L0@W)74egUtKMVCB{ z1{4M-EBON#R#p#XLj9iDlQ5uyCcvPGSktFWYl-X^6gZHEd(ASWvfqs~31hCTcLP|> z+dtRf*J^mIsqnuhn^=>gCCxH-$(2>=ATWk`u;C4SaPwrsRy_RjvX?_@VdRdf`VUS!i7IR45s`_WOENI5uK!_P1CUtvcGuo{jZm9F1S zDIr99mH0mxo}nve|E zUS0|o^>mKp!mhAO`}7%`j`SP>it?*?cr1|sj5R>Sew+~wDC`nAGLoMh)e2SN;Sy_x z`A%`3kuza$LS_S4aihyYmikm7ih z3lx*f`2c4^_oYKS`z>81fl12k!ZEvUi_95)=&#Pt&px4@kH=#L96qc<+660vUrejy ztu&($Uj)(5ohRPrsc)VlfP+7!#FKE?K?kRW#E1X z>5@)Q^ozP{{`#gQxwth}TH6uAWkc=Cw7L}M^WxDxR)hN5sh zJr<6V+I|@9qrO~d47QQYs;ErRQm_mm%CHXl9?@+WSMS1fD^h+(!wLf_INt$_=vV#& zhT#xs{KKSM{H^g?CyZ+|4b6{8OyQX7Y5wMFqra+_SZ<0cR=-e?#-q_nyULr|pQHDq zPWH=dLxn_FMl|UU7d+XlK5nG^Q*SUiJDf2}A^khdR)G6&{)=cKxf0xuty}wryRK%F z52@m^pU9u6!1=`w>AC~JYuK!tWU*;33OZIX>*7pp)n$Ki9h)tT5!EMIo#g9sk6ptg zoM18z6^c$nHrxB|)~0sth&Xyxq`Kpud=xG@PcqGxapYOza}z4sTZ!7s6A`&fL+8+B1O`F8KJMuR2nGmrRAh^_GW+S zf*&jV6LQG@b_xBE5Gw8?FGjjJ&jHXz1@k%cPw~0tjX#i?@v2E)ZOM7UYK0Viaa~jwF9vS zPj_^gw)9kJSswXZ42BoeeEvy=vzm2ebO^ilXy3A6sKIWnoPLC~B6o(z$DNYvIzzw+ znPpHE=I3~9i|2xK-|$YAjz=O^I~s<1N4BE zVRJkikBI(0B#58gNm{FEsOjGQbjuZjnvjWdbC+7S-~(A&ebOF5E>BTg-|?hB{u2L4 z7it_(o>p?fC}9k}OryckHHp-CNgwwZ^ZW1{epDSV;q9RekF#xk6StsWD0BrRZedb) z_?b3WReUw;LqGYbeqXx5zOL(z%rJ@sN8fPgmk6JbyJi#cN%vKFPfy~8bDukpLbfn& zQU<)dcGkcI=FomySa%%!4yX%tA+)y-FVUcg>P$EGTe)~rM_1BHVd?IC z+UL5`oLU&d}aTQeW1_pYYboB6ZwZsm@|9FKyh>_6V9Lzr#iH zOK+EN%OB|$q;So=3%7sF?H?>qOXwCXt13^t5uP@sDT9~nt4og+Pt)8^f8N7W&PP=B zw{v}bQjgRzc5K1#uT7$5`2(5BSfr$HFV`tss9CtDLuhXdR!pBKPo|99&%%g?_?_CF zN%HE+S zRhL^Y>))LqJ~1p$TuL-#Oh}e6Y@)v;4ssk~nB@i9nSZ>I5PETPCVS>cAACH~TS36Y zd1~_dw6|<}4_LrNP9Z97rdZ{HD_|xmNzQ1vK$X%eKvZF8eLtL0ly3@yQ zAnpdgi&X?5X218rjLy6yrAl3FB#*w(G@JrYldmbclM}^StxmUZ^UA^&IZLgtKlxnj zdbW?SZ>1fKe}2mPM9}%~N!=_ZkN+jPR??-)ZOSHn(`!ewT(G zjh{Zd9>i3f0<}&IQll5o5Qz&Od*y}Z>YeAFx}y|*9(zV~%kkf+YCe#ph}z#bz2~xl zVS1I9XdTINdCI9OgF$ZFxcwDcq%F5&q(Uf#WSHy#|M_po{wM+U|ecz3^ z{rT)p;r8Tt^--~xRaha#!ArU3PQUS*clLFkgfZx`3%at2VHV`|;3X|iX=8*5PQ6u< zqUu(4UY|hq*DSr;WC_1-cNyYm3&k>=5Oux_+ zZjGYlU$@m7D;RB>wIfI^a}UN_VN$yktng;jSak3Py%yrTdW-!^8OAOvFVB023}~pQ zukFyGn>)zK>1ddPurR^J(U6F6Z<{l-#_07Vl2nIU>8Z}}zcaC(=sh%=G^8X?<#pcr zP!L@>RXSK4r?insXh$vpqj9DRGAYb5F*u0Y`8Ye*P-?Z4tUpoJI+thlQJmKKSgfUf zxoqEjWfXRuzMiZy=bFggLr0E>o{Y^k84^Ld2_jK4qINC#wb;Jl6yh{!B0nxli|VYf zXo)PPe_>e`HIiI0kDEo}z*X~N508<#Os~bNl-VCDU3v;+KJ;!@>V>|~eswFW!5E(5 zWj&-yop47)wGytaw+QjzDC^Mu$K0m*qHLy{BU}17FdQ^!d7MwRA2Ntsi(;tgJ!pjXJb zigP;&TC{}<$>@)W2cloagt0|d3_68y>o40l>FecYzHzoHAqk}M{+^*hjLF3ZAD3_A z;mx&fJI96EiSCZfNUo2o<5nD6p{TG@O`&>}Y)A33t1+bDV!)ZpFgMgRK?Dk6HEhMZD%*;d| zulio(yk+h4+tAoCL7SK?(5Ub=bg8}nB zJ_%_2LVGC1mhsN*d??e^y35vIrf@KDsJCW$^J|<4l7q;@#ENR|h?7YA?Bt)wOzq0CEL-voyJyt@)LpP{xTBrj==XTap z9WCt2Qork>zwMn2DcW)@1Q_A4;PS^}6g+$StKgrP$%etG-o5HJnZ+qyq?GK4_ejnl-hGiaw1b; z0O}ROP+l^ov`XAAju@yVjEm3dpDskQvReg0O@Xk)QW4!m8|k71I|`?1GBGWMXAQ|6Mo zLe#MkAKpe$++ZL5`dBOhe6qwj?F;8^72lP}pwsqr_;l4{Ol$07E*Ijh7B zT^Z1I5t@mFJi#$PDAXD^9F5%(n@l zO3m$EvZXPulb0`;68+%Lmv=kZuUck^d?LbipIuw8X?Q$d3)5v=*miGI>GM$Lpl!E9 z>}s2Pmj4+s_*^-gZ*@(JYUbe<;?n)3vD=0~B{)%<&TMew8YYaIkX8|W47gkCdFSB! zK20O=Z-Mv5IXbspT#3%6fNNj2d(&h;y7j(jItU``V)460Y|4}T33^{ci*@c};bl;; z?VC*x>z|LcUWtzcaMB4rLiqAa1XpATk zcvtXx7moY#AvDRQ(;vFA#qWCk^Q+njrFXf@~ z@{!_8W_1ygmJFk#_BNl6p7vbX0L69nISz*Olb7clc?DSt5*TK)tiNn4McjUsZ52XC zu3B;drtvHWg-Bom`F104a4cO<#nA1kgp~l-k!X+lJB&?M?lH#c7581619K(H?0bTQwN`J zs^y!x^xPXatOwX!>^;gMgxDEfV;MMDKY9OW^03kGw>Q=69h>u-XS(oU>gK)A!|qh* zYF|KCitaSJ`V(9x+gNDW$X`!lE09qp!m%Ua@DKIIecpSS%0S}GwNI(A5g-Z1;lr3wiJ9)HjQH?jo2akar!aAa&du}<6&$6R>t;(mbJ9?7xy=8DXD^%r6e(9kB$wJ zx;OP6TeM3Q6-0-`apSCK6`Dm^n|6!6>-}!_4w7$n!NX~9mo{Ly4zYNLFNpWy#l_gW zUmn+gaeHUPZPf3p~}$@%|<%q(E?SxMYf%6tJ+o~NC=2~ zmE5~ivRm0CM^B>2$;<*d7MDxzoeib~Svxl4B-}%rh`Q;t2-7wEHQlqn6VAtqQTaIS$5J}_ zDt4%+t3l#=yM;a)vYJ$PBN9O^j4J`*>SK%pFZrDg_EqQ{s2^<$!I+MWtyPga z*DbQg2}(~W8T2oYVYQV-M#fPR{jedSc?3qpSz`@6U1q7y`V8;-`nREC1hE=$qXuto zB;cDVMV0R=k0}>zsLv-!1cQG|1GBc*N`sm8A<4zI!c3@`NUeJH_txag&y=ux4@t9> zjIzMz`6`Z-d6eggF^$AeGvJ$d1BMp|u=7mS`lib?8+-kvmyyc1-<2V4Q4WDzC9Q8I zCtUvAkvbM@EvT~MCiyWCEB;L5x#=emGkJbgK$&;X8@RGYZ3V}4xv;#NAU(cK<$Mu! zk~Ca!HL$?1OGm}-uljB5QQWbx+gf*6ce>+_d6zD@K6 zUUM zy{*ZH{eT+x(5W2xniwXi@twGr+j1Y_wI+03j5Rx=fRst{$IalUY>pe^9yIefZs$8G%JtjQXiaMu9RL(nv12^85@^} z{9hiOIpsjVvNEAYMjTyiGaddy4o)$UW1H7Fo@YvSM>EP|VZKzp{y9xI8+7_!r*oyN zCNHDTl06F71#~y7S`Khk2@_TI$0_9CbbgmL==DkQd*;}96Ac~f-pYoT9JQ8fRi;99 z$U_z>i`4k#@ND|h-i?u=C!7r|=HHb)1Z6a2y*n>}vKmjOtTJ!yU5HF*!yL*sj{XN&6x-Me63=QZ~Ps zj^t5gT!)+!HdVoB4*TQ0leoPZK?=wXkqt^K~l;o`R@{)Rp7l?g)LF_RaS7CFh*#Rm)ZtEH-Ms8m8bpFG`F)YB_{RzCAj zUpr>Sww_frs6|tsZ^Ub{MK*LXktMU*$_<2n^6F+QZoRJHZQ<2ac|>f2+rpsZMk2co zn-l=&ZSZ@-FWH{?r$|IY(Jfu>zv_+Aia9zaDo>oC??h-s$$4a{r~L{ILHZj ZPegCQZ-8fk{bz-}6yK=GR!W-%{}+D diff --git a/matisse/src/main/res/drawable-xhdpi/ic_gif.png b/matisse/src/main/res/drawable-xhdpi/ic_gif.png deleted file mode 100644 index ed2a70be64b73b78b3b11e2c2c288fca73fbffb7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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 diff --git a/matisse/src/main/res/drawable-xhdpi/ic_play_circle_outline_white_48dp.png b/matisse/src/main/res/drawable-xhdpi/ic_play_circle_outline_white_48dp.png deleted file mode 100644 index 516f6432693ac6d89901a2c9a0e76baa01045808..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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 diff --git a/matisse/src/main/res/drawable-xhdpi/ic_preview_radio_off.webp b/matisse/src/main/res/drawable-xhdpi/ic_preview_radio_off.webp deleted file mode 100644 index b13bb1bd8cd14e87284b293b92aac64266ee76c9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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- diff --git a/matisse/src/main/res/drawable-xhdpi/ic_preview_radio_on.webp b/matisse/src/main/res/drawable-xhdpi/ic_preview_radio_on.webp deleted file mode 100644 index 632b2a7351067900bedf2bb3cc9ee67097f35e01..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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 diff --git a/matisse/src/main/res/drawable-xxhdpi/ic_arrow_drop_down_white_24dp.png b/matisse/src/main/res/drawable-xxhdpi/ic_arrow_drop_down_white_24dp.png deleted file mode 100644 index c19c19d2bd2709454a29d9140d5d0a1ff51302c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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 diff --git a/matisse/src/main/res/drawable-xxhdpi/ic_gif.png b/matisse/src/main/res/drawable-xxhdpi/ic_gif.png deleted file mode 100644 index 2803825a9d32f01a4edac4a58cb62ee3be3c356d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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 diff --git a/matisse/src/main/res/drawable-xxhdpi/ic_play_circle_outline_white_48dp.png b/matisse/src/main/res/drawable-xxhdpi/ic_play_circle_outline_white_48dp.png deleted file mode 100644 index 0311f899dd60c1856b10b4af459409309444aad9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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 diff --git a/matisse/src/main/res/drawable-xxxhdpi/ic_check_white_18dp.png b/matisse/src/main/res/drawable-xxxhdpi/ic_check_white_18dp.png deleted file mode 100644 index 2c2ad771f72c8beaa5adbff66526893d8767990d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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 diff --git a/matisse/src/main/res/drawable-xxxhdpi/ic_empty_dracula.png b/matisse/src/main/res/drawable-xxxhdpi/ic_empty_dracula.png deleted file mode 100644 index 4fc34d81016bd1734489a090bdd0f2a9fa74f1fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17923 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 diff --git a/matisse/src/main/res/drawable-xxxhdpi/ic_empty_zhihu.png b/matisse/src/main/res/drawable-xxxhdpi/ic_empty_zhihu.png deleted file mode 100644 index 9b3c3f1884955d12a1f2becb1b39bab5fd9351d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17553 zcmeIacT|(z*ER?dlp?(fQbc-3={2B$NL2)+gY+7DZ&3jO0Tn4i=t?irdqAp)^xh%# zPN)F_d^Zm~?>F<$%zD>)XU)u7zdu|UlAN>mwcB;}**9StYKjDSG7ycq7C&mhnCm1)>)R-%@FnwZ+YawS*$~^w*aKv$p7!j;$ z|Dm%8WYmN!@6k=DWZ&8TaKn@!PH^v*5_h=8_-CH(zy7enGk?#iqvZTE(d;_))Btp? z<@%Jb+VSyu&TKfYY^iElan0JuM{LWz!s?FXH@mv~&#iptWbi3{Y|G+wLA&d^ebb$*{=5s=wb- zUngUz9yU3+!e!&*b$+&f8wAS1)g``lovk(UftT8j$t2eaT$NY@L+Anio11iQOQC@= z{HO5o^~!0uAiOkIbJ@GsX&zh%ywt04SGd+xP!^0i^q%_z^m?BhEimRQuBx6JAy{$P zgAzYs3*1CT1s;2l?b67-Ya#luFtIhrN*Qn8?4u35ESwU5cwJKx8PhOqHOQczG-!C_wFp<=>M%^Yv&l4h3q=sxHWP;&in zME?$!!h&xYTb4Z^y)HJR_$jzC|`eTr$Nu*LR_y(a`z-sPF8=*I5`Uu!XAeR{D z#!T_ROJ1Av8~7qg05h>tfF4|9vQ7$^iKUR?20j6h^zGS%S2*8!KvWD<@dj=t#`?_^ zR#eynyo7%eaE7=507vy9bi~gF1#vIAuYl}(gPGl=2a`-EyS98AAWYkoz5KOl%U=Vg zMJ(bbU(3eMnufu-Y{_-AT^ryAlx*s&HwF;^j3*$Xf8$U*lo}WnqTX_B*OG?gvIm9N zjECPSSpsO))=4IQqofMpGJm_ZZx)IG{FX;8r4RQXrJ-*?%OI|0%Y1r#$-rfU($d-) zGt4KcRZUL(&v@$=o9bKoWT4vk>_K|T(!YA2m`L_~>9>}QE;>}2s|Uw@W(22w2k>UW zbWpp|NgdD$4hu`T(TM}l3D?^7Mkjwjr=um6)*Dfj0G*V;NjKnZkpVjKSuwF*>+~EC zMePT?d#pZ(cz5;%H7j?u!xj)a6(XKYsWIThEZ242s;i|mVgVVnlx+VsawMR?P%bI^ zjsCH~OHQS&8zUD2My_Dh0@|U1}`H(tr-pcn}xanpXE_baJuoAJz$%?5WSmBrU&?}t#0#sa3f(ouuXkBU6r6IvXa9#)h2F;d zsE}zcNH4!%?yhDd?rtFjj} zm=QqapAT3UHaWJbOS8*s@Xmk6fU>7y>`4RBGYpC$mpQ?pkga*I2m+9vxrK#Ou5FTt zU}N~s#2&x7a`jP*DKCi!#1W~( z6^D@}FnwJIf0CgC1Y6)BOpGcDi{q^eVKkN=58&GFr&zO!&~CtR7s6Ds4jch4cGt4j z0kUrOq^|n1URj&0yadNq9~q<1_0|P98fyY51-6jwr!$YC)8VPG3{`mz{fN{ly=#5c z0DUC(S=Uo=RbHYOnH|{QP8gvVN3KnD1ej(T@3`ns?Tq~Lx9Jxn>pZR(DNIDc3qNv*R05B=s%qScGF&K}@0ARe9ur;@3u zxON$Dz!J+#PoGMW<&>d1ZLD;$0I`?$qr=nirTi4rIDoga%;oMkkS8c2W1jS8-~edV zQb}{Z&4rdqbC zQ~=nyjB-R8stQu&4%pibCzlORHGtGA%J;b$jj;0LV`BGlzp79&p@p(i$#_=}{_}p} zSSC|WLQ)~lD;9thJbx*HMmM4zPm1-bx$EWZ?hqx5Yho5sIIoR!qt3`j5bbxhBYF&nSWa&YoSH0`ih zfvTpOVNM6a#+m@qQp>c#l^(I7RD#mgM3+C%D*W(*5IT^s; z#;fXw8lkk#W?1b?BMGmukX8}JtF zdHWmcUakX(Gcy$iyQ$Ye&gaCj`j_=L01F;1t1aG?Sy>>;WJQy1_}#xW=Z4?m0hAZ7 zdHmnAMlldp4K-w9H}zTraO5jD`lqmheXlZ8ck=I>dj0l_-{Fh~chgIr4-Jo>{(&a9 z@6}zdK%@iEDCa>n2xjc2MD7&Ke3XF9-=fE z?&ib2vxifS&-Rp!0v95Cw-0SLd65+H_X>e zfD_0sT7Pl{ZYTr+0GhD5(#IQJe*iC^iwXUUw``Mt(8MPe0paH+52gYwZ2F_sGQSLz zncSW?+oc3y{lP`?81?jyNReNeQ0!-8=q(X*U}3jsfSuCKd+gZfL&5{ePvNc|7iG*- zI)!k3HkmWD-rm3xT_zGBHNH50Cnt}00#OGs71P_2s)Jr)?K*s&zf0}?T|el?&A9Ko z>s)Sh_nstzbpdng%1$amO;L^e0w;pHAF8&i0EZ!ka-;ud?Vo)k@aHpP7do|dcAMXa zKh!X2O3JHF=D9Ii9AIy~L{Za!j}3rH+qUeLZdm9mK-_^=+@u?~;sxBw(MtISp&uY= z?2&<1A&yOMrQRQ%MX3q?to1&XMF}ldI*1M(!r|f6030_pMpfI3Z{55EGL`dTneI>)zQx`Lyv#o*xX}c@opBGgYvRbD%JXh#*9-&U5je zfDLa2ppe-YXS+IGd_z|&KLrA!p6G_+&ESfHhU&gT=$$-<9gq1WtDX7-J=YInd{b)i zM0k7$9od@Nb@%qV8%`7d(d92d7X)|i{w=%Y_8)f?u_g@eo=sq`2Wn`wzvy4DL*}h= zi{yT5*vE~e@k}0WM8ONjneX1F)Q~2}2jH|Ez>jiZTRvR7&Ev6vC+a~uAanav)FI<@ z#r0^!$sHyTh=#S%y<$K2_vH1+*wi9Q9) zRFIw72xqvrB>j1VAl*e-X*a>ZK@oFj^JQ|}e71*A+x|b^YC;cy?42X>y;r};cj-<( z&eHs#x)JU6y>eH~uTd$58L3(2CDr^YkB%{IpNsq4Q$%HE#xDq4gR}r=$Qv5c=EFML z(SMEz1acL?5p|k`{?B2Km-g04_~vZ?F9EqZl#!EbU{Jg-`?oD%bVU?g*<5ZgNCPln zgmvFwaD-R=?WwP;NY!t3m}rU95|@!H_te>nQzDB_*1H1faTZJ)i*4W<^lG-Nuftp>FY(l}GXH1Klt6Y+;R01~yNeh>F;Zp6Ogp(-JaV zyo`SNCg(8_=-n6<`Kl?R$Z!69H9knI0p_!fbW}}7{(>Mc2rH3?I6Q5bSvAn^D@&u( z!S1lSkc3{p5YPY_8u}~9T@)>|*V+{y`i_X%#zntHjtn?y`BVJg@5Cwbd)0wu-|go?U@olY0>NIZ%+07Ii0FX^7l_i_49fs( zI^mU|$S35$j}8i%?(XQ{I0w3nDiI$2CJAshYScS;FXTPQ>^OuYXe3)zE!k%;+??a& zviam_Njh@!H7>DrJUA{Aew@`(j0V?bP;NgSI1*H3^ zK7R!(MCL~j$olzDcp*I@$;?od04*PI#wEi^Rg)Tk=g3Q{1N1`jP`}SJ&N9A&QRM+C zW1lP3iKlN#ij5!50qCar_R!%_@Sa~0#7x)-gf+qTi6wVdYfE|3;Gs4~cWfhevQ=hu z1>^IpZ+b%Q(QN)~{1TdWDRikPCE8Cpe=Fctlf20s=$|q{Jk8;2@R=WNmV#c`x@M9CKG{I} z`%82&Tc@$`1KZ+Kqj3`oaO{ht%=A!o8RUot*17$c9}qkS3B%QnoX9U2P)l6%RBEg7 z;(&`>_4A2j&zXC+jQG$s0E@w-aV8wU#e+3vUYeaitw$PXi3`Dz-jk&=DpX?0rkNyW%iXuSIfk)j%Vs7 zXt5bGTq0?WJX_f0$mjL(p{H1zZtG>+4(bf2sE2$EgaZtCjRyhjs)M80A7mi{cVQS% z2dq-7GVYUedsxHH<;8iRGXjNNSa8tZBZoc*aE*1bwJ&RuBJ$fSw0VTyNMH4K^)l)& zyVo%aoQL^7Sp*8G4FtMaTAb^^&kseU>&~C2uxQ*g5%jUP{pb2G1z{6DRzT$0dv{)S zY!Xx$m3!U~S~NSt`Fu(>e_~zsB z?KXQ6>Qc2wT@c^N&%>P}<*d+YK)$*&FLw~MZb!PpZMC-TQUJDo3Ta-S(IiXI4aR`3 zVKw)ssYjJoFree~qhX1T%64R9Mom4ozEr(x?7QhP*+utwxo7CYQ%BXS!-fHW&`@FQ zGNQKXjAroNa&Ocsz|+Kdpnwpt^0hj2|U2m1^d+T008oBbSk3NYp@+yOje$vV?`OIbQm)6g}g6$<~-| zpj^3~A4K=s__49m)UovLSaFE4|9hu<#Jf%7R8i;kjJ-&kbalY*q%G=NU(2{$n#ll=H0oyH zCIKB96IRf?=b*?|qaV_9#(!@Sp(5UA%?4nftYTO3uJ-t1PzH8);Id{yy8<9%P(18` z1D+~wqrDV7{h?PK*ao+TkXZ3_GY!X59%heJc9aLr1IH`v)q#)d;(sjLr0Z~O*q$!i zRy^CHa>B|v7lV!C2otjLeZMq7K7Ra$fQ(V21U!~|uFfFseJVsDl3zmz6h-lbp}Y{c z{brU%Vjy{HYxzz9joYTbz}|CC0%zHecNFgwQaRxj9CE=sXs0L$QfLlBlF5C473MshaW6nB{k z$Tjay(p@~3MvZN>bUY6k3J^zCt$y-F+x)7+S6}d^KbGmzFkL?Wy z0gum-XH<@9q|DyQ{qZ=tTn#ARh05dhw=RC42l|NK-63{_dkh%_ds0_W~PdJVqaXGdc;54WwZ@xM$_ zq2VpuJ2HZ0gn}vnw29aQ%)a|l$FSOrWk>f>5K#8NMkeg_h+Q*^IfkZAnj{7cE^QG*U_O8mtW{M~i7Tq|O%zogs z#^B&5h2I$*Y`W^3a955|AkGiBOoMH~xw8M*OR^`m=)jq}{r(w!yE9~6(v9wvo^50P z;&Q_jUG^H`wJ>IO7rEg#zUtfJUoLQjKH+3A^W5+CzVGSP>+i4{2J7Wr(SirQ(O-LW z+C4wtpEo&dbbW?0{PCIS3pd)md`-mnN1@K>*Z@L~^b#_20&$R{#Bol3ja67srB$@Vy zEO(B!>gJv)T}+fmxBOxh`x)pxim-A`ay}Q`e*H7n5YZp?E`3MzA~`&@+rQO)PtqX( zzB=lyA9G~r&=bn@*PC0ui>IVMdZ)^JsovnA&LO$Mwo0dAL0jH&0pgmI-xhnsSo3p5m4ut8zTL;&vq{f-X z`uh_J7o$(PpCU-oA9cC>63**7F>gCs7U+>#iCA)_pMjKoNb$&JS{XbNTRNTPUpm#^ zsct&h*^7F2;O;eF49`yzKk_qFo81?197>8d#@07BR-ZC#k+5G(7D}0s zuQ7vkeTJFyyUmil47;H;@-AW^e}u;OfQ?4G zbKdJrP;gU%mX?Xv&THgq8$^n}sumIO!i@8O_6u>o}NOh_kzx4r0 zTHY#WEt{#6XKkN_9MEZG=l;JlW3j$Rh$;OmpLLoZtYGNNq)=WV< z#=2^rC;h6Z%{E)pn;~bP2+laBE%I^8y4MlqWR}A@<{ZsB%rjeWc_!5Qw<_C-v-1)> za`SeWwhqKr2A6YxpW4KUfnH%1WljQ>CvnUsBsQyC8e6-qUQd4V!{GB*B_HuN$J;5o z*R;&qIdWpI}(oLcm8+KUihz}>QK_I7P-$d^I$kU*$Ep1A2=7a;(gUGB4L}a!g7dKlT-*YyWFKIp$P?`(;A(r2vF$7eep1Yf|m5 zi<(7SNTJ^b&Tsx{$4Yh1d!OtWN99?+a!G2Gze(kSZlgbo+E;G7lsKfLScsBHsSQVJ zSF~nwL}bn@%+{&qlPnkzC}JRNTJqx1?AowZm#Q_E3}4AN6dgv(A10TpvwOTn9dr(? zrUc}`X zg!`?qy4cTtPtiTnh+7 zooF*Qg>{-VweKaZj03WnGML(L%!RM`mp1fQRlso|rB!eh@iTI;R3O=Rg2p==68I?8Rg!;FK|R<|$XUg1O=E zg8@+ATyQn2Be*X%ys}E*s>`9Hv^d{x5(%u!a%=eN*8eRS)fWo-Eny0@|A&r6J^zro&uUEoZI{`(n4i44$h8uC!-xYl1p8 zT*K(432!erVOfv0d=8Cnc2rqEspwRBCj?eoTbj2XC-x% z34F7G{dOOWaR!Zwe%>fhgbRGOqhZrL*IRKe9ehFU>jzt6TG{VB;da%_*%}f82TzGt ze+K2eQ%d%FwwC6Z-SlR@q`o?#wIez1_1yx0i;?5x5sp1SZm+mF${0V&v#p5_@?aR! z-`$~bZ@fD`p7KjuaBw67k_}%d*x|~zi=~1_;J29DIGdUQA3lxhZG-FRjK&=HTW4$G zNy+rWIx_6MQ^bgtBjy7?n$<1&A;pqlkWpi@6nxV7Y5(Ktma2v=hhcbsBEP7B3UG;% z7@lv(mEBN#M`MblEqT{SnfsNnhn{J+|Iw5!iy|wfoc@{IrNq{Uy#&ODK>KU{R=C*< z4UaHI!y`VvEj_o_0PH}Ivit$CSTrleEIdww=i&`MS~bf za4pK|vD?%G1{{gSQe{cRV=<+DqiyXYK0eO}>|K+z43=}bn z{;G>0`Ir&h^s;(8%Nmo^EDHN|zZ@earab;$In+3MiRZQ%m1NzMwCa(djFm7NoZ0>-5HMap8FFwIw@G1`n*Ey9BmYQ_}m zL$ZHA+FDE9I%S_YMtsdq0T_Y_ZOa_R^dD~Ifw3fk*w&*R7!}WJk?68WvDy29gN=my z&~Jp9Yf5E7+eGy?_Rgs!uM!mVGR8{D| zdEn2@8g3B!N^rT*nS7(pU_Q1(L(o&cs_QH=TK*hRpc^T2z9C3geLLr7>HJY(X-mG{ zU(o@3;k#@;HLg#}h|1iEScv5ODlVBunc}5DUp$S{^1j@ zsVAfIYQB`?tUHi>vwi{cX-C&tEIBr=7Xzm|0YR;vjz@UQ-G8BPY*1_w>yAbnP~7pWr+W9GBfWRUAP*_3%5Ed z0=Luj)Kr~Cc>>kTr|Cu6JC>6?cuRhhaan<-*4yEZ#~C;gO^rF9Z_9kH#i{)@p35VM zt>G}#z0R&$cZvIxoqlCB?+wQznb%YIv`U_EPAI?zGQ(MVqJ_6!>ds>C>1g#tln*Au zboOVy9rA{$?F#V|R`H#OS;pM|M+U+*h&IOpL@^ zK4i5jW#uANvK^iBUEB*APbsD!#3rkA0lqrTCv*BGS74I?{V8IG+J$ z2iS-*xk-r^myb9{3T6bE0j1#^OwBAWNvf%EN|Tl8hz>ZZWo)#(O8*a)p3F%}S9-Qm zp4zY7-u(e9KMiXGFO{e6Iuq`yuD`?_`ffi&qbyT|`A4a@sDOOpUI!>+wLi7^kj~Pb z&q!t>E7dz9qA-Sor~3k6w;ZhBSl$~!E_B?PM})^SOV!!wadY>) z&tUB#pj_z;*QB(cLJE806n7+B)*pTUo12>KLKX2z7PTSSLm_nc95VGoyiv=2Qv%(q zF01mAeQT)Kqqidyv@t*NwJmu6aXDnF1eNdKpdp$=K_SOVO<)W| zOLQZCdJ-&+=8Y!CaL`ma@5O-eDYO{BO}%7XDoHp2glwgA`KYK?nr(HzMV@wGwESIOx`%FHQ^$XeFm&6-;snii5D8T@C6c*Vq-uFEO;rE$qPe&JqMbIiFl*ki z5aqB3M(V;RI`}h}ei3oYn}kL28;1NgY_lvvtM8R0e)Y&}yRnSYqa}_Lod6 z&n^*jh_-Bc^dOt#I^^v!eGSMOlG#)EIg3?p%itx!2MlN~)_}bRifMKJ;ul}&Lm3hE zVbgA|P)$GM#-E~I#bLt!}gS{l+0?=lVnto(%F`?eCo;jygpT zm!6N7`X^2u4dfHeYAGA@Y(B*tYW^NeAm#_k7V(7g+F1biY2ut3P70`BPRJyEmM@mG zLwR0yceStTpIPmC=hK`>BqhM$BFS((vDn>6+^TI_(%T6vW8ixZavxY1Q}QR<_e*jD4@5f(?t) zZ0c(Mil1W5mu8$^EvaaRR_VFNw_t01R%Zqw1}uiT~eP0WyHm&DA0=a%FHm zCg)pvzbhTN>L=PRR?QnJUZS!#icelYd}jyNz)QQ$oZds+6Uh9iA)`n75E%J{vf^>` zWCs`B5_j234@DnOYq}d65U?=idO2^!_PU}fznaXg_hqBsN!P-m%*m#X z6sFz@5yVM(lCD}8!u-Vbe5vRPP6 zRyKXqDGJRC1`lGtAt7h0h}@6rwu9GY(KFTlN#RkKJUqaiVg^kI3;ZHiKzftYu!}ZDa*9B{KL-F9G*rDqL5?Q~6KYTsN_&-JsnT z$*z@yuZxz__XRhA*n#(&;1+GYSZdlfMNNoixl)LCZVjgJgHrBqr%bD??|DLOfvh|% zTA3Z|wn-26HMjHbOQYLGL zjX3l6|Bf-iD?3lah~4MGFXgR!xX;613|XH72&-*+%yu6^Ys0`-#z7A>6#kC`Ryfnv^Ru^k<*{KHr^DQ)Fx}ei3F+w z|Ief3&T*1dJ}$qjShus>Gcj!S6fEh~6a8#P49gqNQIorWYqaDwCdtP4QKL_gWV0P{ zhFAleo5WAXs}`QI%vU5$Ka zqG|)7H**MXvW)lneShLF@Q1tsMaqE4!&7&-h06&YVzU$xHcbx|jrO08zaVJ0yX3u> zKv!Fkxdq%)SAj)ec=3uIZ%VmGBU;0HH+|Q-s2n@L6qLm?y{FwSVt%)ooYfamq#IV0K1RY=qxf@X0ORC6<6mFo>!)Q`|9GS0jqQ|dZAGENUtz& zl)-QJ*SnTmI_UG=2VXtk%WP8B`pM6q*s%;Q4lSr($XEN!u|eS5eP{VD1*OUDsUUpF zmtHNgxynkR=k2lndJoV``;dusMn_;!;njmr77Kw|@)9xS&g(V^~XzvcpdIO_5fpuXEHb8SyI?As!%*nl-Tzb0X0{yt&|PL7QGV%B&<;)G`LCnuL;X7M z&Zr4vf-fs=kU|$YeTAWo^B3IRGxz4?`e(Y9;JxQ3r+lxZ_JU5-^BgsOfqNqBci?LM z0hv6mo?!p@Hgy4!0AmTeXs7<;4a@0{@~tW+4iRJD?mC5qe*Na$w2P^7PG$K0ZHax) znAnx5Y44T%9@V5Vpgn)wCUaTgWWLpV)wc!KUHt+^E$kdePy3vw4hdyBCmLw$7!&NQ z>}9oiUcA}LlCMyfWMl9@U^xr91EG&D^{*=!nTT(8Znk%DI2^2+K_w2F5PZ4mdPV&_D^L{xy8!|@Z}xqdd|5>b`ZMBcw@Mdyl&MGdEuNrI&# z6kye6J74Y{LeFvOTBpvAW<^AFr9U?U7;tMc0?p?fU!Jz>7oX)ejO3pl@<%WE&x@x` z<~dfWZUuAb1&I6IzlcvFcjZ!p3gH$gm!Mm>s)~apo?Jdd{rEZa!};FTOiU%-dpiy3 z!;?e4^Qn=Q4OBpRN`n+S#jr55SmEe1%kf1IX&{HTE`VbuR+}*3ecPH?`OPm^A zNJ!M*2Vhjv)Xv~Nj+&f7P0&h9@`c=CI4=_+3T+9b@u(gB%N0^{kYv$V6=1p45l!Dv z>3nMbkADIUlF3>C-2Q8jWHI32?c7SgV_HLMdB~cFa-|QUtmY zPH%hxY!r+C{vk=AI#N^2&Wh$0hC6HQ(jAwTtEgiEg;>Ua)RnaX3Uh0X1X{!<8i?FfR7Aaxl33KrRs z<0!7c`+f{VFRFGr&3DiL?&Fzv91wZ`WMDK~$w$8M#p*{4Xb+CPis9$)sRWAN^xa<$ zJ~MZ2clH#VBTLK_;eFp^X?{;#4G#I@)!qZwJF?eomPXvR!>8ioBRqC@{i+}z1l9s& z_9MKi1GZ0Aj-pcoH~KUAUJV!BJdFYf2y`F+rv_U7A6mzU`_qxvW+cODZilq1o$zZ^ z)~D|+3*2;q(k7U~FBw%!trQlJor_a}=->UBipJLFpWf!F&JE>iDsSLZH3o=MPo=PQ za@lTpg+>k7qYY5!9>%4Q;Ky#RHq1;}BSRS4Wh)trO`pHN+ z&|d|QjY|p8M+Y3lZ5W-%vYwNBts-T7r}=5?MU(~~s*?TwvKgTphaTzM;zo(2_I|g;^BEk35sz@uQYJcyKm6ps^4X5)+|(+>jFAl2{{9O!stab-!L~5r zgu&;!!WW%MgvR?^uIolsQlw6LKTJE}_VaUfa?iq3LzaGM&I7X}fmc&Y;zF$N#LQnEGwRH2OBYKKml?KYRyX&1!i{{I|mqw@}#zi$Fvz$jh&rK z(GHXF$|&m9U_`c z_^pR`;&w0Wwd(b&{U=EQ0{V{hP@?fLMX@EDF$JRWOl~cw$r=XRTM{xD zo#&H{6XjNAEA2L?7g_QwDcislJ5Ai6+hI-PXN&P{TFN-5+K2pjEAW6;0+PCzJ|zX0 zm1NJNXvOi#7;gP<=I7o;F_G;u{#V0;-H&hkA73^7e@Zflxh$RxFHX_QksM4C;H!#m zQF+-*DZ`iIT0*NYseLgpuw<_O7Qp>;n?T-d`d{55_kFA-pTosqmVqYgk#=K@Q#i;q zZd(5x)zQYi1|hd>e2`N0$lrli&^rt#2Z#7AZIdnDB`ptLxC{?H6_PC4?QFIhDLYtf zUUy|6!alNXX`z_;h>ehfB03N)!TrTu1Di{aw;g+zTVC<>Mt(VfZ~moH6Mt007Ekg2 z{V4wLO4!E$Eth#B^b(k~NA*37Ht_4*opWg6_B|9;Mc1>vt8gw2u-&TZ4MZGGLX0v%!rRmtE?TM~lZh2em7}l0`uL)zt`<(&GVReKBV(KNoEH zy557{37+KQ>QvBRg6M$9PTbkQg~-ii6w^-AL|t%yN_ak3Vd@ZnOGVz&0<;C(|5wO_ zDuCzmLGu|a%J9=jK2}nkQOqqOsz^Sy^3qs1y@n2)2*eG3p4KraP&+F;$}B|+{i zDD!ZbfuO2VY!VXOslc#(=b)*E&wo3fRew?sD6&dGNC1yw;6oXm4nlNf5(}dnA9j^? zKsULG!&3uei;DcSCFFMO7b!r7l)IgwyjG)QK0Ho)i=DT+;sd5Vi3WacnOa@u1u%M@d*F_y+Q29aeV#EhMcvSg4#A|vIf zETiH!wo15j!j(fLTa-vB+wFcE_ni9&+}AnJ`}6s}zt8#n@OeMyJn1B&1xid&41ypO z!4hu=Dib_bB5KGKE6%^78Wc_ovZlfq{V`At4toT!@N_YHVz5YHEs(j*g9ujgOB{ zOiWBkNl8sjWwBTp85xA+T{mvrxOMARSy@?m zd3j}JWkp2=hr_9^uCA%6sjaQ8udlDGtK)LHPXx5IwD5Smwzjs8j*iaG&Y77RpkU@J z0X;oEd_I3}Ztl~kPknuT0|NttgM-^TG&D3KV03i!>({U2U0q!TZ*6RBfFtO?3s_rQ1J1Sy{2xDltPWQVf~czL zc0_v!wi6*Ei@_=>YaRLR*l|Og=_xB~>z|q0**l#9i~Wh~f4KdNySuxGfU^Lwe2OPn zzn8bSw~vpnuP>GA=LdqIfjs;J0ze+;&IJVrp9iUghJ}ZR)9E0bh=|C@NRSZ7CgxIX zY+PI%gTZ7na!p_gh?VxA%0*hKE%*BOP6G*TK(6NZpsp$*cO}`C6m8p6O1$5SF$qs>nQ-*mG>o z^VgTUb9LB)2Thu&YVx#v*iHW2bZ&UcKZb~hJo+SnGO^{}8PW;8ST$Sf$yPw?_ z{yVcAvC9k>K?+}B1hI<{%oDB|El5oYh4TW^)MDoJ%2F`94m4@LD~G?ERL3F2`(T(9 zad{P4>MYc4s*Z%D##;+N?_(>wT6f50DwOM?M1dvl}|jwP11>qdkh|ZY39N%xjOHg$S=*7bv*s> z9pYjlYt=%BhX|3wzP*D8!C;#!5Txhp=yeXvq1O0GfxghwVtN0#6=?sxKR?$CS<<6d zpbr)2rST0#=3z-&m@Ok{eQ`i^?{IsuQNaQfy(4cK;;W4iB%v)-=4cjlr53X8*}HOY zcd0108I9&dW(SvM8+R|nOZd=rFHR~eV%xGi!*Q{?~^j`ONA}?`~ zIYuvLefTE&chL{d;3cziLrF4>wD zw~U;V9BB78J5Z{h_jj5VrJ_oDL(PHLYJ&S@vYpEN2+%BMrA(Lb0;d2~TbCUuR6O)8IzMOVjlwCgu?v#@fNn w%9O=J*+#9Qh3(Q;l2)S9e3g|Z)-+axeICs=5C0`+`SU+RFel<`OeqQf02u-iSO5S3 diff --git a/matisse/src/main/res/drawable-xxxhdpi/ic_photo_camera_white_24dp.png b/matisse/src/main/res/drawable-xxxhdpi/ic_photo_camera_white_24dp.png deleted file mode 100644 index 777658e95515ca47c9852d00621e2e6d45abc5c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 894 zcmV-^1A+XBP)zI9LJx5Cecy~F=}h8lwKtS@9n)MRxm2`AkqpItJs@p>)C(tu-V-#=CId=UD(s^ z#Zy@d`v;fOn~Tzu?OJHHNtIePI-lk`KN@Bx3G-g)`+Uz|m=FBkykXu`7K_DVu`~_~ z1Z4r$j3}CsFA0vr7p4ddb45K=_{;=>kNJmsIpZVU0%^)LLWz`4fe-nOMmgjIT>|g$ zGtFS1ZXE(|^ApYDN8W0_z#v8Txj;7;?6E~Um_R#sF$;$xalZoX{D6r(A?{D$E~c{O zM_>?haY%a$6fv1Q-U9oW%qwq!3ryzRTflV87q9|W;F{;GFv0){qSYiAAj>K*xHezl zfJJ&yHS#`7{A#YiA58NG$|F%`I5JV-9to7sbaLM;flIzZ1Lw!X3#^Fu{wYByi=R|$;R}qoTB8JI$kiVUUtqx1 zx=B!Su6`5*yii_yR9b4GhtSXus6)G54OU*Fzb<9Fuf)`*nQG!IEfB;+M}w za~X69{6e&@G0KTnj6*#FFeADVZuofoh-l4&E`cLDWuFO3wP#-rPc_|?^a;Rylnh;L z@)wd48zfOOJOnKQa*Rac43Xn8&v?osa%9ANUyhGPfeM+%FRSSkfU`OkhV}j2l~kBT z1bVSYwP7Nn+I` zNiohkFLCTaw-vAgjq*RZ@U(}??0O4qVKTS91=2W}ibKjn!0?Ng1(Y9wI8QK9r3~STT*`8Ja=(^@g{hDdO`4j= zTyvR_E>qNuTx#U9kjQU6zrTKeoO3?se9q_nKIf0~d7U&j7h4Ij-C_U$NZ8w19~D~G zAAv!Idj0L)OaKu3Xm4$K{4$8&c1;)qDCJu<@-^T;N1&)BZaeD%d(!APRm;H<8$wKw zwob)2j{DvycVwWFEGE?454-n2P}`A&Q`oOrms0pOl--SzS50;B@E-O-`RHJeyCbv= zhpoLGv7iSEC$*o7+!P$Rwf0+daD~k_o{4+Kc|RkiGiQ4BqcK%-f*^fjtaGbz*(5}9 z0_9U$m4njSFmjczGP3&5SVQKa^D+yx zAWatZ-9<_5mO~xupF=6ZmkV$okeekntu25jJxM3#mR2hjxJg!xf6a7``7Nq2V3MDF zBJrHoz-J)5@bzKNrATx`{7$!COB#)uzA1K5T6-r#4Wh4$KLd7}hPnThn)VanC*6uX z(OR$b0hG>3_IzFHZ#vkJX;ODD-BIg)Dp*XDR^(X2JN4D8`_!k(0)5|@+wIjm7>WCP z#@Cp=5H=TyOUepVmwJ+-H?^SGZL7;tjP2B zPjZo+9XBJSLU6qv7C+p@hMbyAPPQp@R%P8w3+r(yepxAv>E8W>o>P)0x){6Zv06ZV zwJUgC*L4Ycx6fB8!h81^6G+NZrztObJ25%ZwpNWsd+oUUoUast z*+fM2%iHP67ZawS3mY{Oj+DK#ZQ~wCuqrpF)=fC!zOQ0xmp2n?zEA&*j zHk$*MB(7zD2GuRCpG~_m)P@#7j9LYyyfBJkeX!LbMV5#hc4N|>@4KeQg64Bdx&DI? zpu)%|B|gbHG5oiPSJJq4DjH-Jkv<*p?89R~)#&;_XlEHvVQllOey(Du43OYBuk9rS zxeSx}3jz&-sevitGi0`m=ELFtP$d{gjeue03F##NwYcw)MnAd~97p-BWkMNn_zqF* zn4YG9g}E`D__<4z3uKctQ50bt)%8=ZL@W&Qu$?5r3j?-}O?ABQFlMQ+k(utW^62#L zy!MCV{XpfT?PhAK6)BiP1B7xJj$j`}#mR7wkoyD>%~IM0@^q|B`7Zi*=`CPS zRkb)>_7n87INk6EM3YK;R1~tR&I)HM4@s5(m0n1UVrKw0cXdiC(1bbEKs&y7aSU>t zSU8Q`0vxKUp(V>>kg?=ZEo%$P2Q8DV(I3sC3^aXSNb5T6!Y-UrE|;ax2wCsYeiWHe z<0$WSPv1uqmQdO+`ESP{jYN;CKi+uuX!aOHv5kLf3rMe;HDOE6D05My6MtabB}f{P zQbQ@D_x=S{U|;PqW5ux3h1K4n9c9M~@2;QBy9#t2(+AVVn?>!29_4>9W&H{j#r!0P z%H{oLp;zw3B>w#mJnYS;`XNC;5QNv;P5K=$J0#xlSpQ6_gjqVL`lqJ9e*BaI(KjeRhj~|e_u(Lc9U}ZH^njJ?gjWDgyZU}6DRh< zIkgOQ-`|jMuL{Jk(kObH%UW>3uxv;wY&@p}NZqVQ1FvD}$qVoLhiThMA6==7<+UD%pDLH)n zd3fX(LHr)BIGCp;6Btgt^f%ZF_Z9wSE;WL@e+j03BW)J;W; zY!6Xxow}sh-5&AlureVC=N$FVS=q_>&5`GFE(KKm9IU&rtP$6yqwzg0nXBuA59C** zwVu3v8IN-icJRE{CeaLE^&zQj2|XEroT6pS*}Vb7CV!TWZS{B*>hA4WQ@r8UuS%}W z7*irCBD(-9mHm^{5q_Xqe>3%4HF4*?%yJ6&h+Ci61xEJAldobwtV@1p_FTjjSGe!I9<_LJ-wl-3mMpVPH$QNXrD)0dz`8AQ3l!_0 zi5rn-j+cu)N85-l%a9gtjD5biU>Txe%#LIBjo^v<&i*#<+D?f3%SpJxQV7)v!KMsz kTWBoE0t7=)fd5l0U|9-H=YsoR{@G^jZCtGDto#!H3-tvgssI20 diff --git a/matisse/src/main/res/layout/activity_matisse.xml b/matisse/src/main/res/layout/activity_matisse.xml deleted file mode 100644 index 821a0b3..0000000 --- a/matisse/src/main/res/layout/activity_matisse.xml +++ /dev/null @@ -1,137 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/matisse/src/main/res/layout/activity_media_preview.xml b/matisse/src/main/res/layout/activity_media_preview.xml deleted file mode 100644 index e9fc349..0000000 --- a/matisse/src/main/res/layout/activity_media_preview.xml +++ /dev/null @@ -1,130 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/matisse/src/main/res/layout/album_list_item.xml b/matisse/src/main/res/layout/album_list_item.xml deleted file mode 100644 index 1fc8d2f..0000000 --- a/matisse/src/main/res/layout/album_list_item.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/matisse/src/main/res/layout/fragment_media_selection.xml b/matisse/src/main/res/layout/fragment_media_selection.xml deleted file mode 100644 index 5298172..0000000 --- a/matisse/src/main/res/layout/fragment_media_selection.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - diff --git a/matisse/src/main/res/layout/fragment_preview_item.xml b/matisse/src/main/res/layout/fragment_preview_item.xml deleted file mode 100644 index 2cfc58d..0000000 --- a/matisse/src/main/res/layout/fragment_preview_item.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - diff --git a/matisse/src/main/res/layout/media_grid_content.xml b/matisse/src/main/res/layout/media_grid_content.xml deleted file mode 100644 index 711557c..0000000 --- a/matisse/src/main/res/layout/media_grid_content.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/matisse/src/main/res/layout/media_grid_item.xml b/matisse/src/main/res/layout/media_grid_item.xml deleted file mode 100644 index 392e38b..0000000 --- a/matisse/src/main/res/layout/media_grid_item.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - \ No newline at end of file diff --git a/matisse/src/main/res/layout/photo_capture_item.xml b/matisse/src/main/res/layout/photo_capture_item.xml deleted file mode 100644 index 9c30942..0000000 --- a/matisse/src/main/res/layout/photo_capture_item.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/matisse/src/main/res/values-ar/strings.xml b/matisse/src/main/res/values-ar/strings.xml deleted file mode 100644 index 784cc64..0000000 --- a/matisse/src/main/res/values-ar/strings.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - جميع وسائل الإعلام - - معاينة - تطبيق - تطبيق (%1$d) - رجوع - كاميرا - لا وسائل الإعلام حتى الآن - تم - - لقد وصلت إلى الحد الأقصى للاختيار - يمكنك تحديد ما يصل إلى %1$d من ملفات الوسائط فقط - تحت الجودة - فوق الجودة - نوع ملف غير مدعوم - لا يمكن تحديد الصور ومقاطع الفيديو في نفس الوقت - لم يتم العثور على التطبيق دعم معاينة الفيديو - diff --git a/matisse/src/main/res/values-ca/strings.xml b/matisse/src/main/res/values-ca/strings.xml deleted file mode 100644 index 0611d09..0000000 --- a/matisse/src/main/res/values-ca/strings.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - Tots - - Previsualitza - Selecciona - Selecciona(%1$d) - Enrere - Càmera - Cap arxiu seleccionat - OK - - Has sobrepassat el màxim d\'arxius seleccionables - Només pots seleccionar fins a %1$d arxius multimedia - Baixa qualitat - Excés qualitat - Tipus d\'arxiu no permés - No es poden seleccionar imatges i vídeos al mateix temps - No s\'ha trobat cap app que suporti la previsualització de vídeo - diff --git a/matisse/src/main/res/values-de/strings.xml b/matisse/src/main/res/values-de/strings.xml deleted file mode 100644 index b92112b..0000000 --- a/matisse/src/main/res/values-de/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - Alle Medien - - Vorschau - Auswählen - Auswählen(%1$d) - Zurück - Kamera - Keine Medien gewählt - OK - - Sie haben die maximale Anzahl an Medien ausgewählt. - Sie können nur %1$d Medien auswählen - Unter Qualität - Über Qualität - Dateityp nicht unterstützt - Sie können Bilder und Videos nicht gleichzeitig auswählen - Keine App zur Videovorschau gefunden - diff --git a/matisse/src/main/res/values-es/strings.xml b/matisse/src/main/res/values-es/strings.xml deleted file mode 100644 index 5339a3b..0000000 --- a/matisse/src/main/res/values-es/strings.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - Todos - - Previsualizar - Seleccionar - Seleccionar(%1$d) - Atrás - Cámara - Ningún archivo seleccionado - OK - - Has alcanzado el máximo de archivos seleccionables - Sólo puede seleccionar hasta %1$d archivos multimedia - Baja calidad - Exceso calidad - Tipo de fichero no soportado - No se puede seleccionar imágenes y vídeos al mismo tiempo - No se ha encontrado ninguna app que soporte la previsualización de vídeo - diff --git a/matisse/src/main/res/values-it/strings.xml b/matisse/src/main/res/values-it/strings.xml deleted file mode 100644 index fbf5082..0000000 --- a/matisse/src/main/res/values-it/strings.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - Tutti i media - - Anteprima - Conferma - Conferma(%1$d) - Indietro - Camera - Nessun media disponibile - OK - - Hai selezionato il numero massimo di elementi - Puoi selezionare fino a %1$d elementi - Sotto qualità - Sopra qualità - Tipo di file non supportato - Non è possibile selezionare contemporaneamente immagini e video - Non è stata trovata alcuna app che supporti l\'anteprima video - diff --git a/matisse/src/main/res/values-ko/strings.xml b/matisse/src/main/res/values-ko/strings.xml deleted file mode 100644 index 7612d66..0000000 --- a/matisse/src/main/res/values-ko/strings.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - 전체보기 - 미리보기 - 카메라 - 비디오 미리보기를 지원하는 앱을 찾을 수 없습니다. - 이미지와 비디오는 동시에 선택 할 수 없습니다. - 적용 - 적용(%1$d) - 뒤로 - 미디어 파일이 없습니다. - 확인 - 더이상 선택할 수 없습니다. - 최대 %1$d까지 선택 가능합니다. - 화질이 너무 낮습니다. - 화질이 너무 높습니다. - 지원되지 않는 파일 유형입니다. - \ No newline at end of file diff --git a/matisse/src/main/res/values-pl/strings.xml b/matisse/src/main/res/values-pl/strings.xml deleted file mode 100644 index 739aead..0000000 --- a/matisse/src/main/res/values-pl/strings.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - Wszystkie Media - - Preview - Zatwierdź - Zatwierdź(%1$d) - Wstecz - Aparat - Brak mediów - OK - - Osiągnąłeś limit wybieralnych elementów - Możesz wybrać do %1$d plików - Poniżej jakości - Powyżej jakości - Niewspierany typ pliku - Nie można wybierać obrazów i filmów w tym samym czasie - Nie znaleziono aplikacji wspierającej podgląd wideo - Oryginał - Zatwierdź - Zatwierdź(%1$d) - diff --git a/matisse/src/main/res/values-pt-rBR/strings.xml b/matisse/src/main/res/values-pt-rBR/strings.xml deleted file mode 100644 index 75447a0..0000000 --- a/matisse/src/main/res/values-pt-rBR/strings.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - Todas as mídias - - Pré-visualizaçao - Aplicar - Aplicar(%1$d) - Voltar - Câmera - Nenhuma mídia disponível - OK - - Você atingiu o máximo de itens possíveis para seleção - Você só pode selecionar até %1$d arquivos de mídia - Abaixo da qualidade - Acima da qualidade - Tipo de arquivo não suportado - Não é possível selecionar arquivos de imagem e vídeo simultaneamente - Nenhum player de vídeo disponível para reprodução - diff --git a/matisse/src/main/res/values-ru/strings.xml b/matisse/src/main/res/values-ru/strings.xml deleted file mode 100644 index 2be64f2..0000000 --- a/matisse/src/main/res/values-ru/strings.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - Все - - Предпросмотр - Применить - Применить(%1$d) - Назад - Камера - Пусто - OK - - Вы выбрали максимальное количество файлов - - Можно выбрать не более %1$d файла - Можно выбрать не более %1$d файлов - Можно выбрать не более %1$d файлов - Можно выбрать не более %1$d файлов - - Слишком низкое качество - Слишком высокое качество - Неподдерживаемый тип файла - Невозможно выбрать изображения и видео одновременно - Приложение для предпросмотра видео не найдено - Оригинал - Применить(%1$d) - Применить - diff --git a/matisse/src/main/res/values-tr-rTR/strings.xml b/matisse/src/main/res/values-tr-rTR/strings.xml deleted file mode 100644 index 671e3fb..0000000 --- a/matisse/src/main/res/values-tr-rTR/strings.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - Tüm Medya - - Ön İzleme - Uygula - Uygula(%1$d) - Geri - Kamera - Henüz medya yok - TAMAM - - Maksimum seçilebilir değere ulaştınız - Sadece %1$d medya dosyasını seçebilirsiniz - Düşük kalite - Yüksek kalite - Desteklenmeyen dosya tipi - Görüntüleri ve videoları aynı anda seçemezsiniz - Video önizlemesini destekleyen hiçbir uygulama bulunamadı - \ No newline at end of file diff --git a/matisse/src/main/res/values-uk/strings.xml b/matisse/src/main/res/values-uk/strings.xml deleted file mode 100644 index 97cea27..0000000 --- a/matisse/src/main/res/values-uk/strings.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - Всі - - Перегляд - Застосувати - Застосувати(%1$d) - Назад - Камера - Пусто - OK - - Вы обрали максимальну кількість файлів - - Можливо обрати не більше %1$d файла - Можливо обрати не більше %1$d файлів - Можливо обрати не більше %1$d файлів - Можливо обрати не більше %1$d файлів - - Занадто низька якість - Занадто висока якість - Непідтримуваний тип файла - Неможливо обрати зображення і відео одночасно - Застосунок для перегляду відео не знайдений - diff --git a/matisse/src/main/res/values-zh-rTW/strings.xml b/matisse/src/main/res/values-zh-rTW/strings.xml deleted file mode 100644 index fc77408..0000000 --- a/matisse/src/main/res/values-zh-rTW/strings.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - 全部 - - 預覽 - 使用 - 使用(%1$d) - 返回 - 拍一張 - 還沒有圖片或影片 - 我知道了 - - 您已經達到最大選擇數量 - 最多只能選擇 %1$d 個文件 - 圖片質量太低 - 圖片質量太高 - 不支援的文件類型 - 不能同時選擇圖片和影片 - 沒有支持影片預覽的應用程式 - 原圖 - 确定 - 确定(%1$d) - \ No newline at end of file diff --git a/matisse/src/main/res/values-zh/strings.xml b/matisse/src/main/res/values-zh/strings.xml deleted file mode 100644 index 853ea42..0000000 --- a/matisse/src/main/res/values-zh/strings.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - 全部 - - 预览 - 使用 - 使用(%1$d) - 返回 - 拍一张 - 还没有图片或视频 - 我知道了 - - 您已经达到最大选择数量 - 最多只能选择 %1$d 个文件 - 图片质量太低 - 图片质量太高 - 不支持的文件类型 - 不能同时选择图片和视频 - 没有支持视频预览的应用 - "该照片大于 %1$d M,无法上传将取消勾选原图" - "有 %1$d 张照片大于 %2$d M\n无法上传,将取消勾选原图" - 原图 - 确定 - 确定(%1$d) - \ No newline at end of file diff --git a/matisse/src/main/res/values/attrs.xml b/matisse/src/main/res/values/attrs.xml deleted file mode 100644 index 852a3e3..0000000 --- a/matisse/src/main/res/values/attrs.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/matisse/src/main/res/values/colors.xml b/matisse/src/main/res/values/colors.xml deleted file mode 100644 index 24ec1f9..0000000 --- a/matisse/src/main/res/values/colors.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - #CC000000 - #61FFFFFF - - \ No newline at end of file diff --git a/matisse/src/main/res/values/colors_dracula.xml b/matisse/src/main/res/values/colors_dracula.xml deleted file mode 100644 index e8bb64f..0000000 --- a/matisse/src/main/res/values/colors_dracula.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - #263237 - #1D282C - - #34474E - #DEFFFFFF - #89FFFFFF - #455A64 - #4DFFFFFF - - #37474F - #263237 - #FFFFFF - #FFFFFF - - #232E32 - #34474E - - #DEFFFFFF - #4DFFFFFF - #03A9F4 - #4D03A9F4 - - #FFFFFF - #03A9F4 - #4D03A9F4 - \ No newline at end of file diff --git a/matisse/src/main/res/values/colors_zhihu.xml b/matisse/src/main/res/values/colors_zhihu.xml deleted file mode 100644 index 4cf43fa..0000000 --- a/matisse/src/main/res/values/colors_zhihu.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - #1E8AE8 - #176EB9 - - #FFFFFF - #DE000000 - #999999 - #EAEEF4 - #4D000000 - - #EAEEF4 - #1E8AE8 - #FFFFFF - #424242 - - #FFFFFF - #FFFFFF - - #DE000000 - #4D000000 - #0077D9 - #4D0077D9 - - #FFFFFF - #0077D9 - #4D0077D9 - - #808080 - \ No newline at end of file diff --git a/matisse/src/main/res/values/dimens.xml b/matisse/src/main/res/values/dimens.xml deleted file mode 100644 index f32d77a..0000000 --- a/matisse/src/main/res/values/dimens.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - 48dp - 4dp - - 72dp - \ No newline at end of file diff --git a/matisse/src/main/res/values/strings.xml b/matisse/src/main/res/values/strings.xml deleted file mode 100644 index 819a12a..0000000 --- a/matisse/src/main/res/values/strings.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - All Media - - Preview - Apply - Apply(%1$d) - Back - Camera - No media yet - OK - - You have reached max selectable - You can only select up to %1$d media files - Under quality - Over quality - Unsupported file type - Can\'t select images and videos at the same time - No App found supporting video preview - Can\'t select the images larger than %1$d MB - %1$d images over %2$d MB. Original will be unchecked - Original - Sure - Sure(%1$d) - diff --git a/matisse/src/main/res/values/styles.xml b/matisse/src/main/res/values/styles.xml deleted file mode 100644 index c1f9441..0000000 --- a/matisse/src/main/res/values/styles.xml +++ /dev/null @@ -1,86 +0,0 @@ - - - - - //====================================== Theme Zhihu =========================================== - - - - - - - - //===================================== Theme Dracula ========================================== - - - - - - - - \ No newline at end of file diff --git a/media/.gitignore b/media/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/media/.gitignore @@ -0,0 +1 @@ +/build diff --git a/media/build.gradle b/media/build.gradle new file mode 100644 index 0000000..3e2f2fb --- /dev/null +++ b/media/build.gradle @@ -0,0 +1,53 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 28 + + + + defaultConfig { + minSdkVersion 15 + targetSdkVersion 28 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + +} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + //annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0' + api files('libs/systembartint-1.0.4.jar') + implementation project(':compress') + def versions = rootProject.ext.dependencies + implementation versions.rxlifecycleComponents + implementation versions.appcompatV7 + implementation versions.supportV4 + implementation versions.constraint + implementation versions.recyclerview + implementation versions.projectview + implementation versions.glide + implementation versions.design + implementation versions.PhotoView + implementation versions.eventbus + implementation versions.ucrop + implementation 'com.android.support.constraint:constraint-layout:1.1.3' + testImplementation versions.junit + androidTestImplementation versions.runner + androidTestImplementation versions.espresso +} +allprojects { + repositories { + maven { url 'https://jitpack.io' } + } +} \ No newline at end of file diff --git a/app/libs/systembartint-1.0.4.jar b/media/libs/systembartint-1.0.4.jar similarity index 100% rename from app/libs/systembartint-1.0.4.jar rename to media/libs/systembartint-1.0.4.jar diff --git a/media/proguard-rules.pro b/media/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/media/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/media/src/main/AndroidManifest.xml b/media/src/main/AndroidManifest.xml new file mode 100644 index 0000000..75f2268 --- /dev/null +++ b/media/src/main/AndroidManifest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + diff --git a/media/src/main/java/com/example/media/MediaSelector.java b/media/src/main/java/com/example/media/MediaSelector.java new file mode 100644 index 0000000..e2b97cd --- /dev/null +++ b/media/src/main/java/com/example/media/MediaSelector.java @@ -0,0 +1,131 @@ +package com.example.media; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Color; +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.ColorRes; +import android.support.annotation.NonNull; +import android.support.v4.app.Fragment; + +import com.example.media.activity.MediaActivity; +import com.example.media.bean.MediaSelectorFile; +import com.example.media.resolver.Contast; + +import java.lang.ref.SoftReference; +import java.util.List; + +public class MediaSelector { + private MediaOptions mMediaOptions = MediaSelector.getDefaultOptions(); + private SoftReference mSoftActivity; + private SoftReference mSoftFragment; + + private MediaSelector(Activity activity) { + mSoftActivity = new SoftReference<>(activity); + } + + private MediaSelector(Fragment fragment) { + mSoftFragment = new SoftReference<>(fragment); + } + + public static MediaSelector with(Activity activity) { + return new MediaSelector(activity); + } + + public static MediaSelector with(Fragment fragment) { + return new MediaSelector(fragment); + } + + public MediaSelector setMediaOptions(@NonNull MediaOptions options) { + this.mMediaOptions = options; + return this; + } + + public void openMediaActivity() { + if (mSoftActivity != null && mSoftActivity.get() != null) { + Activity activity = mSoftActivity.get(); + Intent intent = new Intent(activity, MediaActivity.class); + intent.putExtra(Contast.KEY_OPEN_MEDIA, mMediaOptions); + activity.startActivityForResult(intent, Contast.CODE_REQUEST_MEDIA); + } else if (mSoftFragment != null && mSoftFragment.get() != null) { + Fragment fragment = mSoftFragment.get(); + Intent intent = new Intent(fragment.getContext(), MediaActivity.class); + intent.putExtra(Contast.KEY_OPEN_MEDIA, mMediaOptions); + fragment.startActivityForResult(intent, Contast.CODE_REQUEST_MEDIA); + } + } + + public static List resultMediaFile(Intent data) { + if (data == null) + return null; + return data.getParcelableArrayListExtra(Contast.KEY_REQUEST_MEDIA_DATA); + } + + + public static class MediaOptions implements Parcelable { + public MediaOptions() { + } + + public int maxChooseMedia = Contast.MAX_CHOOSE_MEDIA; + public boolean isCompress; + public boolean isShowCamera; + public boolean isShowVideo; + public @ColorRes + int themeColor = R.color.colorTheme; + public boolean isCrop; + public int scaleX = 1; + public int scaleY = 1; + public int cropWidth = 720; + public int cropHeight = 720; + + + protected MediaOptions(Parcel in) { + maxChooseMedia = in.readInt(); + isCompress = in.readByte() != 0; + isShowCamera = in.readByte() != 0; + isShowVideo = in.readByte() != 0; + themeColor = in.readInt(); + isCrop = in.readByte() != 0; + scaleX = in.readInt(); + scaleY = in.readInt(); + cropWidth = in.readInt(); + cropHeight = in.readInt(); + } + + public static final Creator CREATOR = new Creator() { + @Override + public MediaOptions createFromParcel(Parcel in) { + return new MediaOptions(in); + } + + @Override + public MediaOptions[] newArray(int size) { + return new MediaOptions[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(maxChooseMedia); + dest.writeByte((byte) (isCompress ? 1 : 0)); + dest.writeByte((byte) (isShowCamera ? 1 : 0)); + dest.writeByte((byte) (isShowVideo ? 1 : 0)); + dest.writeInt(themeColor); + dest.writeByte((byte) (isCrop ? 1 : 0)); + dest.writeInt(scaleX); + dest.writeInt(scaleY); + dest.writeInt(cropWidth); + dest.writeInt(cropHeight); + } + } + + public static MediaOptions getDefaultOptions() { + return new MediaOptions(); + } +} diff --git a/media/src/main/java/com/example/media/OnRecyclerItemClickListener.java b/media/src/main/java/com/example/media/OnRecyclerItemClickListener.java new file mode 100644 index 0000000..7644952 --- /dev/null +++ b/media/src/main/java/com/example/media/OnRecyclerItemClickListener.java @@ -0,0 +1,8 @@ +package com.example.media; + +import android.support.annotation.NonNull; +import android.view.View; + +public interface OnRecyclerItemClickListener { + void itemClick(@NonNull View view, int position); +} diff --git a/media/src/main/java/com/example/media/activity/BaseActivity.java b/media/src/main/java/com/example/media/activity/BaseActivity.java new file mode 100644 index 0000000..93616f3 --- /dev/null +++ b/media/src/main/java/com/example/media/activity/BaseActivity.java @@ -0,0 +1,95 @@ +package com.example.media.activity; + +import android.os.Build; +import android.os.Bundle; +import android.support.annotation.ColorRes; +import android.support.annotation.Nullable; +import android.support.v4.content.ContextCompat; +import android.view.WindowManager; + +import com.example.media.R; +import com.example.media.bean.MediaSelectorFile; +import com.example.media.permission.PermissionActivity; +import com.example.media.resolver.ActivityManger; +import com.readystatesoftware.systembartint.SystemBarTintManager; + +import org.greenrobot.eventbus.EventBus; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import utils.bean.ImageConfig; +import utils.task.CompressImageTask; + +public abstract class BaseActivity extends PermissionActivity { + + protected SystemBarTintManager mSystemBarTintManager; + private @ColorRes + int mThemeColor = R.color.colorTheme; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + } + setContentView(getLayoutId()); + initPermission(); + + } + + protected void initPermission() { + ActivityManger.get().addActivity(this); + initView(); + initData(); + initEvent(); + initUI(); + } + + protected int getThemeColor() { + return mThemeColor; + } + + protected void initUI() { + mSystemBarTintManager = new SystemBarTintManager(this); + mSystemBarTintManager.setStatusBarTintEnabled(true); + mSystemBarTintManager.setStatusBarTintColor(ContextCompat.getColor(this, getThemeColor())); + } + + @Override + protected void onDestroy() { + ActivityManger.get().removeActivity(getClass().getSimpleName()); + super.onDestroy(); + } + + protected abstract void initView(); + + protected abstract void initData(); + + protected abstract void initEvent(); + + protected abstract int getLayoutId(); + + + protected void registerEventBus() { + if (!EventBus.getDefault().isRegistered(this)) { + EventBus.getDefault().register(this); + } + } + + protected void unRegisterEventBus() { + if (EventBus.getDefault().isRegistered(this)) { + EventBus.getDefault().unregister(this); + } + } + + protected void compressImage(List mMediaFileData, CompressImageTask.OnImagesResult onImagesResult) { + final List configData = new ArrayList<>(); + for (int i = 0; i < mMediaFileData.size(); i++) { + configData.add(MediaSelectorFile.thisToDefaultImageConfig(mMediaFileData.get(i))); + } + + CompressImageTask.get().compressImages(this, configData, onImagesResult); + } +} diff --git a/media/src/main/java/com/example/media/activity/MediaActivity.java b/media/src/main/java/com/example/media/activity/MediaActivity.java new file mode 100644 index 0000000..c4e5cc4 --- /dev/null +++ b/media/src/main/java/com/example/media/activity/MediaActivity.java @@ -0,0 +1,462 @@ +package com.example.media.activity; + +import android.Manifest; +import android.app.Activity; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.net.Uri; +import android.os.Parcelable; +import android.provider.MediaStore; +import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; +import android.support.v7.app.AlertDialog; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.View; + +import com.bumptech.glide.Glide; +import com.example.item.weight.TitleView; +import com.example.media.MediaSelector; +import com.example.media.OnRecyclerItemClickListener; +import com.example.media.R; +import com.example.media.adapter.MediaFileAdapter; +import com.example.media.bean.MediaSelectorFile; +import com.example.media.bean.MediaSelectorFolder; +import com.example.media.permission.imp.OnPermissionsResult; +import com.example.media.resolver.Contast; +import com.example.media.resolver.ILoadMediaResult; +import com.example.media.resolver.MediaHelper; +import com.example.media.utils.FileUtils; +import com.example.media.weight.DialogHelper; +import com.example.media.weight.FolderWindow; +import com.example.media.weight.Toasts; + +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import utils.bean.ImageConfig; +import utils.task.CompressImageTask; + +public class MediaActivity extends BaseActivity { + + private TitleView mTvTop; + private TitleView mTvBottom; + private RecyclerView mRecyclerView; + private MediaFileAdapter mMediaFileAdapter; + private List mMediaFileData; + private List mMediaFolderData; + private FolderWindow mFolderWindow; + private List mCheckMediaFileData; + private MediaSelector.MediaOptions mOptions; + private File mCameraFile; + private AlertDialog mCameraPermissionDialog; + + + @Override + protected int getLayoutId() { + return R.layout.activity_media; + } + + @Override + protected void initPermission() { + + requestExternalStoragePermission(); + + + } + + @Override + protected int getThemeColor() { + return mOptions.themeColor; + } + + private void requestExternalStoragePermission() { + requestPermission(new OnPermissionsResult() { + @Override + public void onAllow(List list) { + MediaActivity.super.initPermission(); + } + + @Override + public void onNoAllow(List list) { + AlertDialog dialog = DialogHelper.with().createDialog(MediaActivity.this, getString(R.string.hint), getString(R.string.what_permission_is_must, getString(R.string.memory_card)), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + requestExternalStoragePermission(); + } + }); + dialog.show(); + } + + @Override + public void onForbid(List list) { + showForbidPermissionDialog(); + } + }, Manifest.permission.WRITE_EXTERNAL_STORAGE); + } + + private void showNoCameraAllowDialog(Context context, String title, String message) { + if (mCameraPermissionDialog == null) { + mCameraPermissionDialog = DialogHelper.with().createDialog(context, title, message, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + mCameraPermissionDialog.dismiss(); + } + }, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + openCamera(); + } + }); + } + if (!mCameraPermissionDialog.isShowing()) { + mCameraPermissionDialog.show(); + } + } + + @Override + protected void onStart() { + super.onStart(); + Glide.with(this).onStart(); + } + + @Override + protected void onStop() { + + super.onStop(); + + Glide.with(this).onStop(); + } + + @Override + protected void onDestroy() { + unRegisterEventBus(); + super.onDestroy(); + } + + @Override + protected void initView() { + registerEventBus(); + mTvTop = findViewById(R.id.ctv_top); + mTvBottom = findViewById(R.id.ctv_bottom); + mRecyclerView = findViewById(R.id.ry_data); + mRecyclerView.setLayoutManager(new GridLayoutManager(this, 4)); + } + + @Override + protected void initData() { + initIntent(); + MediaHelper mediaHelper = new MediaHelper(this); + mCheckMediaFileData = new ArrayList<>(); + + if (mMediaFileAdapter == null) { + + mMediaFileAdapter = new MediaFileAdapter(this, mMediaFileData,mOptions); + mRecyclerView.setAdapter(mMediaFileAdapter); + } + mediaHelper.loadMedia(mOptions.isShowCamera, mOptions.isShowVideo, new ILoadMediaResult() { + @Override + public void mediaResult(List data) { + if (data != null && data.size() > 0) { + mMediaFileData.addAll(data.get(0).fileData); + if (mMediaFolderData == null) { + mMediaFolderData = data; + } else { + mMediaFolderData.addAll(data); + } + mMediaFileAdapter.notifyDataSetChanged(); + } + + } + }); + } + + private void initIntent() { + mMediaFileData = new ArrayList<>(); + Intent intent = getIntent(); + mOptions = intent.getParcelableExtra(Contast.KEY_OPEN_MEDIA); + if (mOptions == null) { + mOptions = MediaSelector.getDefaultOptions(); + } else { + if (mOptions.maxChooseMedia <= 0) { + mOptions.maxChooseMedia = 1; + } + mTvTop.mViewRoot.setBackgroundColor(ContextCompat.getColor(this,mOptions.themeColor)); + mTvBottom.mViewRoot.setBackgroundColor(ContextCompat.getColor(this,mOptions.themeColor)); + } + + } + + private void resultMediaData() { + if (mCheckMediaFileData.size() > 0) { + if (mOptions.isCompress && !mOptions.isShowVideo) { + compressImage(mCheckMediaFileData, new CompressImageTask.OnImagesResult() { + @Override + public void startCompress() { + + } + + @Override + public void resultFilesSucceed(List list) { + mCheckMediaFileData.clear(); + for (File file : list) { + mCheckMediaFileData.add(MediaSelectorFile.checkFileToThis(file)); + } + resultMediaIntent(); + } + + @Override + public void resultFilesError() { + + } + }); + + } else { + resultMediaIntent(); + } + + } + } + + private void resultMediaIntent() { + Intent intent = new Intent(); + intent.putParcelableArrayListExtra(Contast.KEY_REQUEST_MEDIA_DATA, (ArrayList) mCheckMediaFileData); + setResult(Contast.CODE_RESULT_MEDIA, intent); + finish(); + } + + @Override + protected void initEvent() { + mTvTop.setOnSureViewClickListener(new TitleView.OnSureViewClickListener() { + @Override + public void onSureClick(@NonNull View view) { + resultMediaData(); + } + }); + mTvBottom.setOnTitleViewClickListener(new TitleView.OnTitleViewClickListener() { + @Override + public void onBackClick(@NonNull View view) { + showMediaFolderWindows(view); + } + + @Override + public void onSureClick(@NonNull View view) { + if (mCheckMediaFileData.size() > 0) { + toPreviewActivity(0, mCheckMediaFileData, mCheckMediaFileData); + } + + } + }); + mMediaFileAdapter.setOnRecyclerItemClickListener(new OnRecyclerItemClickListener() { + @Override + public void itemClick(@NonNull View view, int position) { + if (mMediaFileData.get(position).isShowCamera) { + openCamera(); + } else { + toPreviewActivity(position, mMediaFileData, mCheckMediaFileData); + } + } + }); + + + mMediaFileAdapter.setOnCheckMediaListener(new MediaFileAdapter.OnCheckMediaListener() { + @Override + public void onChecked(boolean isCheck, int position) { + if (isCheck) { + mMediaFileData.get(position).isCheck = false; + mCheckMediaFileData.remove(mMediaFileData.get(position)); + } else { + if (mCheckMediaFileData.size() < mOptions.maxChooseMedia) { + mMediaFileData.get(position).isCheck = true; + mCheckMediaFileData.add(mMediaFileData.get(position)); + } else { + Toasts.with().showToast(MediaActivity.this, getString(R.string.max_choose_media, String.valueOf(mOptions.maxChooseMedia))); + } + } + setSureStatus(); + mMediaFileAdapter.notifyItemChanged(position); + } + }); + mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { + super.onScrollStateChanged(recyclerView, newState); + if (newState == 0) { + Glide.with(MediaActivity.this).resumeRequests(); + } else { + Glide.with(MediaActivity.this).pauseRequests(); + } + } + + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + super.onScrolled(recyclerView, dx, dy); + } + }); + } + + /** + * 打开相机 + */ + private void openCamera() { + requestPermission(new OnPermissionsResult() { + @Override + public void onAllow(List list) { + Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + cameraIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + if (cameraIntent.resolveActivity(getPackageManager()) != null) { + mCameraFile = FileUtils.resultImageFile(MediaActivity.this); + Uri cameraUri = FileUtils.fileToUri(MediaActivity.this, mCameraFile, cameraIntent); + cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, cameraUri); + startActivityForResult(cameraIntent, Contast.REQUEST_CAMERA_CODE); + } + } + + @Override + public void onNoAllow(List list) { + showNoCameraAllowDialog(MediaActivity.this, getString(R.string.hint), getString(R.string.what_permission_is_must, getString(R.string.camera))); + } + + @Override + public void onForbid(List list) { + + showForbidPermissionDialog(); + + } + }, Manifest.permission.CAMERA); + } + + private void toPreviewActivity(int position, @NonNull List data, @NonNull List checkData) { + Intent intent = new Intent(MediaActivity.this, PreviewActivity.class); + intent.putParcelableArrayListExtra(Contast.KEY_PREVIEW_DATA_MEDIA, (ArrayList) data); + intent.putParcelableArrayListExtra(Contast.KEY_PREVIEW_CHECK_MEDIA, (ArrayList) checkData); + intent.putExtra(Contast.KEY_OPEN_MEDIA, mOptions); + intent.putExtra(Contast.KEY_PREVIEW_POSITION, position); + startActivity(intent); + } + + + private void showMediaFolderWindows(View view) { + + if (mFolderWindow == null) { + mFolderWindow = new FolderWindow(this, mMediaFolderData); + mFolderWindow.setOnPopupItemClickListener(new FolderWindow.OnPopupItemClickListener() { + @Override + public void onItemClick(@NonNull View view, int position) { + clickCheckFolder(position); + } + }); + mFolderWindow.showWindows(view); + } else if (mFolderWindow.getFolderWindow().isShowing()) { + mFolderWindow.dismissWindows(); + } else { + mFolderWindow.showWindows(view); + } + + + } + + private void setSureStatus() { + if (mCheckMediaFileData.size() > 0) { + mTvTop.mTvSure.setClickable(true); + mTvTop.mTvSure.setTextColor(ContextCompat.getColor(MediaActivity.this, R.color.colorTextSelector)); + mTvTop.mTvSure.setText(getString(R.string.complete_count, String.valueOf(mCheckMediaFileData.size()), String.valueOf(mOptions.maxChooseMedia))); + } else { + mTvTop.mTvSure.setClickable(false); + mTvTop.mTvSure.setTextColor(ContextCompat.getColor(MediaActivity.this, R.color.colorTextUnSelector)); + mTvTop.mTvSure.setText(R.string.sure); + + } + } + + private void clickCheckFolder(int position) { + mTvBottom.mTvBack.setText(mMediaFolderData.get(position).folderName); + mMediaFileData.clear(); + mMediaFileData.addAll(mMediaFolderData.get(position).fileData); + mMediaFileAdapter.notifyDataSetChanged(); + } + + @Override + public void onBackPressed() { + if (mFolderWindow != null && mFolderWindow.getFolderWindow().isShowing()) { + mFolderWindow.getFolderWindow().dismiss(); + } else { + super.onBackPressed(); + } + } + + /** + * 预览图片选择发送事件 + * + * @param mediaSelectorFile + */ + @Subscribe(threadMode = ThreadMode.MAIN, sticky = true) + public void previewMediaResult(@NonNull MediaSelectorFile mediaSelectorFile) { + if (mediaSelectorFile.isCheck) { + //首先先判断选择的媒体库 + if (!mCheckMediaFileData.contains(mediaSelectorFile)) { + mCheckMediaFileData.add(mediaSelectorFile); + } + + } else { + if (mCheckMediaFileData.contains(mediaSelectorFile)) { + mCheckMediaFileData.remove(mediaSelectorFile); + } + } + for (int i = 0; i < mMediaFolderData.size(); i++) { + if (mMediaFolderData.get(i).fileData.contains(mediaSelectorFile)) { + mMediaFolderData.get(i).fileData.get(mMediaFolderData.get(i).fileData.indexOf(mediaSelectorFile)).isCheck = mediaSelectorFile.isCheck; + } + } + setSureStatus(); + mMediaFileAdapter.notifyDataSetChanged(); + } + + /** + * 预览图片返回 + * + * @param checkMediaData + */ + @Subscribe(threadMode = ThreadMode.MAIN, sticky = true) + public void resultCheckMediaData(@NonNull List checkMediaData) { + if (checkMediaData.size() > 0) { + mCheckMediaFileData.clear(); + mCheckMediaFileData.addAll(checkMediaData); + resultMediaIntent(); + } + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + switch (resultCode) { + case Activity.RESULT_OK: + if (requestCode == Contast.REQUEST_CAMERA_CODE) { + if (FileUtils.existsFile(mCameraFile.getAbsolutePath())) { + FileUtils.scanImage(this, mCameraFile); + MediaSelectorFile mediaSelectorFile = MediaSelectorFile.checkFileToThis(mCameraFile); + if (mediaSelectorFile.hasData()) { + mCheckMediaFileData.add(mediaSelectorFile); + } + resultMediaData(); + } + + } + break; + + } + } +} diff --git a/media/src/main/java/com/example/media/activity/PreviewActivity.java b/media/src/main/java/com/example/media/activity/PreviewActivity.java new file mode 100644 index 0000000..6d2cfcb --- /dev/null +++ b/media/src/main/java/com/example/media/activity/PreviewActivity.java @@ -0,0 +1,345 @@ +package com.example.media.activity; + +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.content.Intent; +import android.graphics.Color; +import android.net.Uri; +import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; +import android.support.v4.view.ViewPager; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.view.animation.LinearInterpolator; +import android.widget.LinearLayout; +import android.widget.Toast; + +import com.example.item.weight.TitleView; +import com.example.media.MediaSelector; +import com.example.media.OnRecyclerItemClickListener; +import com.example.media.R; +import com.example.media.adapter.MediaCheckAdapter; +import com.example.media.adapter.PreviewAdapter; +import com.example.media.bean.MediaSelectorFile; +import com.example.media.resolver.ActivityManger; +import com.example.media.resolver.Contast; +import com.example.media.utils.FileUtils; +import com.example.media.utils.ScreenUtils; +import com.example.media.weight.PreviewViewPager; +import com.example.media.weight.Toasts; +import com.yalantis.ucrop.UCrop; + +import org.greenrobot.eventbus.EventBus; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import utils.bean.ImageConfig; +import utils.task.CompressImageTask; + +public class PreviewActivity extends BaseActivity { + + private PreviewViewPager mVpPreview; + private TitleView mTvTop; + private TitleView mTvBottom; + private List mMediaFileData; + private PreviewAdapter mPreviewAdapter; + private boolean isShowTitleView = true; + private int mPreviewPosition; + private RecyclerView mRvCheckMedia; + private View mLlBottom; + private List mCheckMediaData; + private MediaCheckAdapter mCheckAdapter; + private AnimatorSet mAnimatorSet; + private MediaSelector.MediaOptions mOptions; + + + @Override + protected int getThemeColor() { + return mOptions.themeColor; + } + + @Override + protected void initView() { + mVpPreview = findViewById(R.id.vp_preview); + ViewGroup.LayoutParams layoutParams = mVpPreview.getLayoutParams(); + layoutParams.width = ScreenUtils.screenWidth(this); + layoutParams.height = ScreenUtils.screenHeight(this); + mVpPreview.setLayoutParams(layoutParams); + mTvTop = findViewById(R.id.ctv_top); + mRvCheckMedia = findViewById(R.id.rv_check_media); + mRvCheckMedia.setLayoutManager(new LinearLayoutManager(this, LinearLayout.HORIZONTAL, false)); + mTvBottom = findViewById(R.id.ctv_bottom); + mLlBottom = findViewById(R.id.ll_bottom); + } + + @Override + protected void initData() { + Intent intent = getIntent(); + mCheckMediaData = intent.getParcelableArrayListExtra(Contast.KEY_PREVIEW_CHECK_MEDIA); + if (mCheckMediaData == null) { + mCheckMediaData = new ArrayList<>(); + } + mMediaFileData = intent.getParcelableArrayListExtra(Contast.KEY_PREVIEW_DATA_MEDIA); + mPreviewPosition = intent.getIntExtra(Contast.KEY_PREVIEW_POSITION, 0); + mOptions = intent.getParcelableExtra(Contast.KEY_OPEN_MEDIA); + mTvTop.mViewRoot.setBackgroundColor(ContextCompat.getColor(this, mOptions.themeColor)); + if (mMediaFileData == null || mMediaFileData.size() == 0) { + Toasts.with().showToast(this, "没有预览媒体库文件"); + finish(); + return; + } + if (mMediaFileData.get(0).isShowCamera && mMediaFileData.get(0).filePath == null) { + mMediaFileData.remove(0); + mPreviewPosition--; + } + + if (mCheckMediaData != null && mCheckMediaData.size() > 0) { + for (int i = 0; i < mCheckMediaData.size(); i++) { + if (!mMediaFileData.contains(mCheckMediaData.get(i))) { + mMediaFileData.add(mCheckMediaData.get(i)); + } + } + } + mTvTop.mTvBack.setText(getString(R.string.count_sum_count, String.valueOf(mPreviewPosition + 1), String.valueOf(mMediaFileData.size()))); + setTitleViewSureText(); + mTvBottom.mTvSure.setCompoundDrawablesWithIntrinsicBounds(mMediaFileData.get(mPreviewPosition).isCheck ? R.mipmap.icon_preview_check : R.mipmap.icon_preview_uncheck, 0, 0, 0); + mPreviewAdapter = new PreviewAdapter(mMediaFileData); + mVpPreview.setAdapter(mPreviewAdapter); + mVpPreview.setCurrentItem(mPreviewPosition, true); + mVpPreview.setPageTransformer(true, new PreviewAdapter.PreviewPageTransformer()); + + mCheckAdapter = new MediaCheckAdapter(this, mCheckMediaData); + mRvCheckMedia.setAdapter(mCheckAdapter); + mCheckAdapter.notifyCheckData(mMediaFileData.get(mPreviewPosition)); + initAdapterEvent(); + } + + private void setTitleViewSureText() { + if (mCheckMediaData.size() > 0) { + mTvTop.mTvSure.setText(getString(R.string.complete_count, String.valueOf(mCheckMediaData.size()), String.valueOf(mOptions.maxChooseMedia))); + } else { + mTvTop.mTvSure.setText(R.string.sure); + } + } + + private void initAdapterEvent() { + mVpPreview.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { + @Override + public void onPageScrolled(int i, float v, int i1) { + + } + + @Override + public void onPageSelected(int i) { + mPreviewPosition = i; + mTvTop.mTvBack.setText(getString(R.string.count_sum_count, String.valueOf(i + 1), String.valueOf(mMediaFileData.size()))); + mTvBottom.mTvSure.setCompoundDrawablesWithIntrinsicBounds(mMediaFileData.get(i).isCheck ? R.mipmap.icon_preview_check : R.mipmap.icon_preview_uncheck, 0, 0, 0); + mCheckAdapter.notifyCheckData(mMediaFileData.get(mPreviewPosition)); + if (mCheckMediaData.contains(mMediaFileData.get(mPreviewPosition))) { + mRvCheckMedia.scrollToPosition(mCheckMediaData.indexOf(mMediaFileData.get(mPreviewPosition))); + } + } + + @Override + public void onPageScrollStateChanged(int i) { + + } + }); + mPreviewAdapter.setOnPreviewViewClickListener(new PreviewAdapter.OnPreviewViewClickListener() { + @Override + public void onPreviewView(View view) { + if (mAnimatorSet != null && mAnimatorSet.isRunning()) { + mAnimatorSet.end(); + } + titleViewAnimation(); + isShowTitleView = !isShowTitleView; + } + }); + mPreviewAdapter.setOnPreviewVideoClickListener(new PreviewAdapter.OnPreviewVideoClickListener() { + @Override + public void onClickVideo(View view, int position) { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setDataAndType(Uri.parse(mMediaFileData.get(position).filePath), "video/*"); + startActivityForResult(intent, Contast.CODE_REQUEST_PRIVIEW_VIDEO); + } + }); + mCheckAdapter.setOnRecyclerItemClickListener(new OnRecyclerItemClickListener() { + @Override + public void itemClick(@NonNull View view, int position) { + if (mMediaFileData.contains(mCheckMediaData.get(position))) { + mVpPreview.setCurrentItem(mMediaFileData.indexOf(mCheckMediaData.get(position)), true); + mCheckAdapter.notifyDataSetChanged(); + } + + } + }); + } + + @Override + protected void initEvent() { + + mTvBottom.setOnSureViewClickListener(new TitleView.OnSureViewClickListener() { + @Override + public void onSureClick(@NonNull View view) { + if (mCheckMediaData.size() < mOptions.maxChooseMedia || (mCheckMediaData.size() == mOptions.maxChooseMedia && mMediaFileData.get(mPreviewPosition).isCheck)) { + mMediaFileData.get(mPreviewPosition).isCheck = !mMediaFileData.get(mPreviewPosition).isCheck; + mTvBottom.mTvSure.setCompoundDrawablesWithIntrinsicBounds(mMediaFileData.get(mPreviewPosition).isCheck ? R.mipmap.icon_preview_check : R.mipmap.icon_preview_uncheck, 0, 0, 0); + EventBus.getDefault().post(mMediaFileData.get(mPreviewPosition)); + if (mCheckAdapter != null) { + if (mMediaFileData.get(mPreviewPosition).isCheck) { + mCheckAdapter.addItemNotifyData(mMediaFileData.get(mPreviewPosition)); + mRvCheckMedia.scrollToPosition(mCheckMediaData.indexOf(mMediaFileData.get(mPreviewPosition))); + + } else { + if (mCheckMediaData.contains(mMediaFileData.get(mPreviewPosition))) { + mCheckAdapter.removeItemNotifyData(mCheckMediaData.indexOf(mMediaFileData.get(mPreviewPosition))); + mRvCheckMedia.scrollToPosition(mCheckMediaData.size() - 1); + } + } + } + //设置完成的数量 + setTitleViewSureText(); + } else { + Toasts.with().showToast(PreviewActivity.this, R.string.max_choose_media, String.valueOf(mOptions.maxChooseMedia)); + } + + + } + }); + mTvTop.setOnSureViewClickListener(new TitleView.OnSureViewClickListener() { + @Override + public void onSureClick(@NonNull View view) { + if (mCheckMediaData.size() <= 0) { + mMediaFileData.get(mPreviewPosition).isCheck = true; + mCheckMediaData.add(mMediaFileData.get(mPreviewPosition)); + } + sureData(); + + } + }); + } + + private void sureData() { + if (mOptions.isCompress && !mOptions.isShowVideo && !mOptions.isCrop) { + compressImage(mCheckMediaData, new CompressImageTask.OnImagesResult() { + @Override + public void startCompress() { + + } + + @Override + public void resultFilesSucceed(List list) { + mCheckMediaData.clear(); + for (int i = 0; i < list.size(); i++) { + mCheckMediaData.add(MediaSelectorFile.checkFileToThis(list.get(i))); + } + EventBus.getDefault().post(mCheckMediaData); + finish(); + } + + @Override + public void resultFilesError() { + + } + }); + } else { + if (mOptions.isCrop && mOptions.maxChooseMedia == 1) { + if (!mCheckMediaData.get(0).isVideo) { + UCrop.Options options = new UCrop.Options(); + options.setCompressionQuality(100); + options.setToolbarColor(ContextCompat.getColor(this, mOptions.themeColor)); + options.setStatusBarColor(ContextCompat.getColor(this, mOptions.themeColor)); + options.setLogoColor(ContextCompat.getColor(this, mOptions.themeColor)); + options.setActiveWidgetColor(ContextCompat.getColor(this, mOptions.themeColor)); + UCrop.of(Uri.fromFile(new File(mCheckMediaData.get(0).filePath)), Uri.fromFile(FileUtils.resultImageFile(this, "Crop"))) + .withAspectRatio(mOptions.scaleX, mOptions.scaleY) + .withMaxResultSize(mOptions.cropWidth, mOptions.cropHeight) + .withOptions(options) + .start(this); + } else { + Toasts.with().showToast(this, R.string.video_not_crop); + } + } else { + EventBus.getDefault().post(mCheckMediaData); + finish(); + } + } + } + + @Override + protected int getLayoutId() { + return R.layout.activity_preview; + } + + private void titleViewAnimation() { + ObjectAnimator topAnimatorTranslation; + ObjectAnimator bottomAnimatorTranslation; + if (mAnimatorSet == null) { + mAnimatorSet = new AnimatorSet(); + } + if (isShowTitleView) { + getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + mSystemBarTintManager.setStatusBarTintEnabled(false); + topAnimatorTranslation = ObjectAnimator.ofFloat(mTvTop, "translationY", 0, -(ScreenUtils.getStatuWindowsHeight(this) + mTvTop.getMeasuredHeight())); + bottomAnimatorTranslation = ObjectAnimator.ofFloat(mLlBottom, "translationY", 0, (mLlBottom.getMeasuredHeight())); + + } else { + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + mSystemBarTintManager.setStatusBarTintEnabled(true); + topAnimatorTranslation = ObjectAnimator.ofFloat(mTvTop, "translationY", -(ScreenUtils.getStatuWindowsHeight(this) + mTvTop.getMeasuredHeight()), 0); + bottomAnimatorTranslation = ObjectAnimator.ofFloat(mLlBottom, "translationY", (mLlBottom.getMeasuredHeight()), 0); + + } + mAnimatorSet.setDuration(500); + mAnimatorSet.setInterpolator(new LinearInterpolator()); + mAnimatorSet.playTogether(topAnimatorTranslation, bottomAnimatorTranslation); + mAnimatorSet.start(); + + + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + switch (resultCode) { + case 0: + if (requestCode == Contast.CODE_REQUEST_PRIVIEW_VIDEO && mPreviewAdapter.mCbPlay != null) { + mPreviewAdapter.mCbPlay.setChecked(false); + mPreviewAdapter.notifyDataSetChanged(); + } + case RESULT_OK: + if (requestCode == UCrop.REQUEST_CROP) { + if (data == null) { + return; + } + final Uri resultUri = UCrop.getOutput(data); + if (resultUri != null && resultUri.getPath() != null) { + mCheckMediaData.clear(); + File file = new File(resultUri.getPath()); + if (FileUtils.existsFile(file.getAbsolutePath())) { + mCheckMediaData.add(MediaSelectorFile.checkFileToThis(file)); + EventBus.getDefault().post(mCheckMediaData); + finish(); + } else { + Toasts.with().showToast(this, R.string.file_not_exit, Toast.LENGTH_SHORT); + } + } + + } + break; + case UCrop.RESULT_ERROR: + if (requestCode == UCrop.REQUEST_CROP) { + Toasts.with().showToast(this, R.string.crop_image_fail); + } + break; + default: + break; + } + } +} diff --git a/media/src/main/java/com/example/media/adapter/MediaCheckAdapter.java b/media/src/main/java/com/example/media/adapter/MediaCheckAdapter.java new file mode 100644 index 0000000..997fcb3 --- /dev/null +++ b/media/src/main/java/com/example/media/adapter/MediaCheckAdapter.java @@ -0,0 +1,98 @@ +package com.example.media.adapter; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import com.example.media.OnRecyclerItemClickListener; +import com.example.media.R; +import com.example.media.bean.MediaSelectorFile; +import com.example.media.utils.GlideUtils; + +import java.util.List; + +public class MediaCheckAdapter extends RecyclerView.Adapter { + private List mData; + private Context mContext; + private MediaSelectorFile mPreviewMedia; + + public void setOnRecyclerItemClickListener(OnRecyclerItemClickListener onRecyclerItemClickListener) { + this.onRecyclerItemClickListener = onRecyclerItemClickListener; + } + + private OnRecyclerItemClickListener onRecyclerItemClickListener; + + public MediaCheckAdapter(@NonNull Context context, @NonNull List data) { + this.mContext = context; + this.mData = data; + } + + public void notifyCheckData(MediaSelectorFile previewMedia) { + mPreviewMedia = previewMedia; + this.notifyDataSetChanged(); + } + + public void removeItemNotifyData(int position) { + mData.remove(position); + this.notifyDataSetChanged(); + } + + public void addItemNotifyData(@NonNull MediaSelectorFile previewMedia) { + mData.add(previewMedia); + this.notifyItemRemoved(mData.indexOf(previewMedia)); + } + + @NonNull + @Override + public MediaCheckAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { + return new ViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item_check_media_view, viewGroup, false)); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder viewHolder, final int i) { + viewHolder.mIvMediaType.setVisibility(mData.get(i).isVideo ? View.VISIBLE : View.GONE); + GlideUtils.loadImage(mContext, mData.get(i).filePath, viewHolder.mIvItem); + viewHolder.mIvItem.setBackgroundResource(mPreviewMedia.filePath.equals(mData.get(i).filePath) ? R.drawable.shape_media_check : R.drawable.shape_media_uncheck); + viewHolder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + if (onRecyclerItemClickListener != null) { + onRecyclerItemClickListener.itemClick(v, i); + } + /* if (!mPreviewMedia.filePath.equals(mData.get(i).filePath)) { + if (onRecyclerItemClickListener != null) { + onRecyclerItemClickListener.itemClick(v, i); + } + notifyDataSetChanged(); + }*/ + + } + }); + } + + @Override + public int getItemCount() { + return mData == null ? 0 : mData.size(); + } + + static class ViewHolder extends RecyclerView.ViewHolder { + + private ImageView mIvItem; + private ImageView mIvMediaType; + + ViewHolder(@NonNull View itemView) { + super(itemView); + initView(itemView); + } + + private void initView(View itemView) { + mIvItem = itemView.findViewById(R.id.iv_item); + mIvMediaType = itemView.findViewById(R.id.iv_media_type); + } + } +} diff --git a/media/src/main/java/com/example/media/adapter/MediaFileAdapter.java b/media/src/main/java/com/example/media/adapter/MediaFileAdapter.java new file mode 100644 index 0000000..a0009ee --- /dev/null +++ b/media/src/main/java/com/example/media/adapter/MediaFileAdapter.java @@ -0,0 +1,148 @@ +package com.example.media.adapter; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.example.item.util.ScreenUtils; +import com.example.media.MediaSelector; +import com.example.media.OnRecyclerItemClickListener; +import com.example.media.R; +import com.example.media.bean.MediaSelectorFile; +import com.example.media.resolver.Contast; +import com.example.media.utils.DateUtils; +import com.example.media.utils.GlideUtils; + +import java.util.List; + +public class MediaFileAdapter extends RecyclerView.Adapter { + private List mData; + private Context mContext; + private MediaSelector.MediaOptions mOptions; + + public void setOnCheckMediaListener(OnCheckMediaListener onCheckMediaListener) { + this.onCheckMediaListener = onCheckMediaListener; + } + + private OnCheckMediaListener onCheckMediaListener; + + public void setOnRecyclerItemClickListener(OnRecyclerItemClickListener onRecyclerItemClickListener) { + this.onRecyclerItemClickListener = onRecyclerItemClickListener; + } + + private OnRecyclerItemClickListener onRecyclerItemClickListener; + + public MediaFileAdapter(@NonNull Context context, @NonNull List data, @NonNull MediaSelector.MediaOptions options) { + this.mContext = context; + this.mData = data; + this.mOptions = options; + } + + + @NonNull + @Override + public MediaFileAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { + return new ViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item_media_file_view, viewGroup, false)); + } + + @Override + public void onBindViewHolder(@NonNull MediaFileAdapter.ViewHolder viewHolder, final int i) { + ViewGroup.LayoutParams layoutParams = viewHolder.mIvData.getLayoutParams(); + if (mData.get(i).isShowCamera) { + layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT; + layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT; + GlideUtils.loadImage(mContext, R.mipmap.icon_camera, viewHolder.mIvData); + viewHolder.mIvCheck.setVisibility(View.GONE); + viewHolder.mViewLay.setVisibility(View.GONE); + viewHolder.mRlVideo.setVisibility(View.GONE); + } else { + layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT; + layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT; + viewHolder.mIvCheck.setVisibility(mOptions.maxChooseMedia > 1 ? View.VISIBLE : View.GONE); + GlideUtils.loadImage(mContext, mData.get(i).filePath, viewHolder.mIvData); + viewHolder.mIvCheck.setImageResource(mData.get(i).isCheck ? R.mipmap.icon_image_checked : R.mipmap.icon_image_unchecked); + viewHolder.mViewLay.setVisibility(mData.get(i).isCheck ? View.VISIBLE : View.GONE); + + if (mData.get(i).isVideo) { + viewHolder.mRlVideo.setVisibility(View.VISIBLE); + viewHolder.mTvDuration.setText(DateUtils.videoDuration(mData.get(i).videoDuration)); + } else { + viewHolder.mRlVideo.setVisibility(View.GONE); + } + + + } + viewHolder.mIvData.setLayoutParams(layoutParams); + + viewHolder.mIvCheck.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (onCheckMediaListener != null) { + onCheckMediaListener.onChecked(mData.get(i).isCheck, i); + } + + } + }); + viewHolder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (onRecyclerItemClickListener != null) { + onRecyclerItemClickListener.itemClick(v, i); + } + } + }); + } + + @Override + public int getItemCount() { + return mData == null ? 0 : mData.size(); + } + + static class ViewHolder extends RecyclerView.ViewHolder { + + private ImageView mIvData; + private ImageView mIvCheck; + private View mViewLay; + private RelativeLayout mRlVideo; + private TextView mTvDuration; + + ViewHolder(@NonNull View itemView) { + super(itemView); + initView(itemView); + } + + private void initView(View itemView) { + ViewGroup mRootGroup = itemView.findViewById(R.id.rl_root); + mIvData = itemView.findViewById(R.id.iv_data); + mIvCheck = itemView.findViewById(R.id.iv_check); + mViewLay = itemView.findViewById(R.id.view_lay); + mRlVideo = itemView.findViewById(R.id.rl_video); + mTvDuration = itemView.findViewById(R.id.tv_duration); + MediaFileAdapter.setRootGroupParams(mRootGroup); + } + } + + + private static void setRootGroupParams(@NonNull ViewGroup viewGroup) { + ViewGroup.LayoutParams mGroupParams = viewGroup.getLayoutParams(); + mGroupParams.width = viewGroup.getContext().getResources().getDisplayMetrics().widthPixels / 4; + mGroupParams.height = viewGroup.getContext().getResources().getDisplayMetrics().widthPixels / 4; + viewGroup.setLayoutParams(mGroupParams); + viewGroup.setPadding(ScreenUtils.dp2px(viewGroup.getContext(), 1.5f), ScreenUtils.dp2px(viewGroup.getContext(), 1.5f), + ScreenUtils.dp2px(viewGroup.getContext(), 1.5f), ScreenUtils.dp2px(viewGroup.getContext(), 1.5f)); + } + + public interface OnCheckMediaListener { + void onChecked(boolean isCheck, int position); + } + +} diff --git a/media/src/main/java/com/example/media/adapter/MediaFolderAdapter.java b/media/src/main/java/com/example/media/adapter/MediaFolderAdapter.java new file mode 100644 index 0000000..190e94c --- /dev/null +++ b/media/src/main/java/com/example/media/adapter/MediaFolderAdapter.java @@ -0,0 +1,103 @@ +package com.example.media.adapter; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.example.media.OnRecyclerItemClickListener; +import com.example.media.R; +import com.example.media.bean.MediaSelectorFolder; +import com.example.media.utils.GlideUtils; + +import java.util.List; + +public class MediaFolderAdapter extends RecyclerView.Adapter { + private List mData; + + public void setOnRecyclerItemClickListener(OnRecyclerItemClickListener onRecyclerItemClickListener) { + this.onRecyclerItemClickListener = onRecyclerItemClickListener; + } + + private OnRecyclerItemClickListener onRecyclerItemClickListener; + + public MediaFolderAdapter(@Nullable List data) { + this.mData = data; + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { + return new ViewHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_media_folder, viewGroup, false)); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder viewHolder, final int i) { + if (mData.get(i).firstFilePath != null) { + GlideUtils.loadImage(viewHolder.itemView.getContext(), mData.get(i).firstFilePath, viewHolder.mIvLeft); + } + + viewHolder.mTvCount.setText(viewHolder.itemView.getContext().getString(R.string.how_match_open, String.valueOf(mData.get(i).fileData.size()))); + viewHolder.mTvTitle.setText(mData.get(i).folderName); + viewHolder.mIvCheck.setImageResource(mData.get(i).isCheck ? R.mipmap.icon_folder_check : R.mipmap.icon_folder_uncheck); + viewHolder.mIvVideoStype.setVisibility(mData.get(i).isAllVideo ? View.VISIBLE : View.GONE); + + viewHolder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + clickCheckSoleData(mData, i); + if (onRecyclerItemClickListener != null) { + onRecyclerItemClickListener.itemClick(v, i); + } + } + }); + } + + @Override + public int getItemCount() { + return mData == null ? 0 : mData.size(); + } + + static class ViewHolder extends RecyclerView.ViewHolder { + + private ImageView mIvLeft; + private TextView mTvTitle; + private TextView mTvCount; + private ImageView mIvCheck; + private ImageView mIvVideoStype; + + ViewHolder(@NonNull View itemView) { + super(itemView); + initView(itemView); + } + + private void initView(View itemView) { + mIvLeft = itemView.findViewById(R.id.iv_left); + mTvTitle = itemView.findViewById(R.id.tv_title); + mTvCount = itemView.findViewById(R.id.tv_count); + mIvCheck = itemView.findViewById(R.id.iv_check); + mIvVideoStype = itemView.findViewById(R.id.iv_video_type); + + } + } + + private void clickCheckSoleData(List data, int position) { + if (data != null && data.size() > position) { + if (!data.get(position).isCheck) { + for (int i = 0; i < data.size(); i++) { + if (i == position) { + mData.get(position).isCheck = true; + } else if (mData.get(i).isCheck) { + mData.get(i).isCheck = false; + } + } + notifyDataSetChanged(); + } + } + } +} diff --git a/media/src/main/java/com/example/media/adapter/PreviewAdapter.java b/media/src/main/java/com/example/media/adapter/PreviewAdapter.java new file mode 100644 index 0000000..f438109 --- /dev/null +++ b/media/src/main/java/com/example/media/adapter/PreviewAdapter.java @@ -0,0 +1,158 @@ +package com.example.media.adapter; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Color; +import android.media.MediaPlayer; +import android.net.Uri; +import android.support.annotation.NonNull; +import android.support.v4.view.PagerAdapter; +import android.support.v4.view.ViewPager; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.ImageView; +import android.widget.MediaController; +import android.widget.VideoView; + +import com.example.media.R; +import com.example.media.bean.MediaSelectorFile; +import com.example.media.utils.GlideUtils; +import com.example.media.utils.ScreenUtils; +import com.example.media.weight.Toasts; +import com.github.chrisbanes.photoview.OnPhotoTapListener; +import com.github.chrisbanes.photoview.PhotoView; + +import java.util.List; + +public class PreviewAdapter extends PagerAdapter { + + private int mChildCount; + private List mData; + public CheckBox mCbPlay; + + public void setOnPreviewViewClickListener(OnPreviewViewClickListener onPreviewViewClickListener) { + this.onPreviewViewClickListener = onPreviewViewClickListener; + } + + private OnPreviewViewClickListener onPreviewViewClickListener; + + public void setOnPreviewVideoClickListener(OnPreviewVideoClickListener onPreviewVideoClickListener) { + this.onPreviewVideoClickListener = onPreviewVideoClickListener; + } + + private OnPreviewVideoClickListener onPreviewVideoClickListener; + + public PreviewAdapter(List data) { + this.mData = data; + } + + @Override + public int getCount() { + return mData == null ? 0 : mData.size(); + } + + @Override + public boolean isViewFromObject(@NonNull View view, @NonNull Object o) { + return view == o; + } + + @Override + public void notifyDataSetChanged() { + mChildCount = getCount(); + super.notifyDataSetChanged(); + } + + @Override + public int getItemPosition(@NonNull Object object) { + if (mChildCount > 0) { + mChildCount--; + return PagerAdapter.POSITION_NONE; + } + return super.getItemPosition(object); + } + + @NonNull + @Override + public Object instantiateItem(@NonNull final ViewGroup container, final int position) { + if (mData.get(position).isVideo) { + View inflate = LayoutInflater.from(container.getContext()).inflate(R.layout.item_video_play_view, container, false); + container.addView(inflate); + + final PhotoView pTData = inflate.findViewById(R.id.pt_data); + mCbPlay = inflate.findViewById(R.id.cb_play); + ViewGroup.LayoutParams layoutParams = pTData.getLayoutParams(); + layoutParams.width = ScreenUtils.screenWidth(container.getContext()); + layoutParams.height = ScreenUtils.screenHeight(container.getContext()); + pTData.setLayoutParams(layoutParams); + GlideUtils.loadImage(container.getContext(), mData.get(position).filePath, pTData,false); + mCbPlay.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (isChecked && onPreviewVideoClickListener !=null) { + onPreviewVideoClickListener.onClickVideo(mCbPlay,position); + + } + } + }); + clickPhotoView(pTData); + + return inflate; + } else { + PhotoView photoView = new PhotoView(container.getContext()); + container.addView(photoView); + ViewGroup.LayoutParams layoutParams = photoView.getLayoutParams(); + layoutParams.width = ScreenUtils.screenWidth(container.getContext()); + layoutParams.height = ScreenUtils.screenHeight(container.getContext()); + photoView.setLayoutParams(layoutParams); + GlideUtils.loadImage(container.getContext(), mData.get(position).filePath, photoView,false); + clickPhotoView(photoView); + return photoView; + } + + } + + private void clickPhotoView(@NonNull PhotoView photoView) { + photoView.setOnPhotoTapListener(new OnPhotoTapListener() { + @Override + public void onPhotoTap(ImageView view, float x, float y) { + if (onPreviewViewClickListener != null) { + onPreviewViewClickListener.onPreviewView(view); + } + } + }); + } + + + @Override + public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { + container.removeView((View) object); + } + + public static class PreviewPageTransformer implements ViewPager.PageTransformer { + private ViewPager viewPager; + + @Override + public void transformPage(@NonNull View view, float position) { + if (viewPager == null) { + viewPager = (ViewPager) view.getParent(); + } + int leftInScreen = view.getLeft() - viewPager.getScrollX(); + float offsetRate = (float) leftInScreen * 0.08f / viewPager.getMeasuredWidth(); + float scaleFactor = 1 - Math.abs(offsetRate); + if (scaleFactor > 0) { + view.setScaleX(scaleFactor); + } + } + } + + public interface OnPreviewViewClickListener { + void onPreviewView(View view); + } + + public interface OnPreviewVideoClickListener { + void onClickVideo(View view, int position); + } +} diff --git a/media/src/main/java/com/example/media/bean/MediaSelectorFile.java b/media/src/main/java/com/example/media/bean/MediaSelectorFile.java new file mode 100644 index 0000000..7e96d5a --- /dev/null +++ b/media/src/main/java/com/example/media/bean/MediaSelectorFile.java @@ -0,0 +1,114 @@ +package com.example.media.bean; + +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.NonNull; +import android.text.TextUtils; + +import com.example.media.utils.FileUtils; + +import java.io.File; + +import utils.bean.ImageConfig; + +public class MediaSelectorFile implements Parcelable { + public String fileName; + public String filePath; + public int fileSize; + public int width; + public int height; + public String folderName; + public String folderPath; + public boolean isCheck; + public boolean isShowCamera; + public boolean isVideo; + public long videoDuration; + + public MediaSelectorFile() { + } + + protected MediaSelectorFile(Parcel in) { + fileName = in.readString(); + filePath = in.readString(); + fileSize = in.readInt(); + width = in.readInt(); + height = in.readInt(); + folderName = in.readString(); + folderPath = in.readString(); + isCheck = in.readByte() != 0; + isShowCamera = in.readByte() != 0; + isVideo = in.readByte() != 0; + videoDuration = in.readLong(); + } + + public static final Creator CREATOR = new Creator() { + @Override + public MediaSelectorFile createFromParcel(Parcel in) { + return new MediaSelectorFile(in); + } + + @Override + public MediaSelectorFile[] newArray(int size) { + return new MediaSelectorFile[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(fileName); + dest.writeString(filePath); + dest.writeInt(fileSize); + dest.writeInt(width); + dest.writeInt(height); + dest.writeString(folderName); + dest.writeString(folderPath); + dest.writeByte((byte) (isCheck ? 1 : 0)); + dest.writeByte((byte) (isShowCamera ? 1 : 0)); + dest.writeByte((byte) (isVideo ? 1 : 0)); + dest.writeLong(videoDuration); + } + + @Override + public boolean equals(Object obj) { + if (obj != null && obj instanceof MediaSelectorFile) { + MediaSelectorFile mediaSelectorFile = (MediaSelectorFile) obj; + if (mediaSelectorFile.filePath != null && this.filePath != null && + mediaSelectorFile.filePath.equals(filePath)) { + return true; + } + } + return super.equals(obj); + } + + + public boolean hasData() { + return !TextUtils.isEmpty(fileName) && TextUtils.getTrimmedLength(fileName) > 0 + && !TextUtils.isEmpty(filePath) && TextUtils.getTrimmedLength(filePath) > 0 + && fileSize > 0 && width > 0 && height > 0 + && !TextUtils.isEmpty(folderName) && TextUtils.getTrimmedLength(folderName) > 0 + && !TextUtils.isEmpty(folderPath) && TextUtils.getTrimmedLength(folderPath) > 0; + } + + public static MediaSelectorFile checkFileToThis(@NonNull File file) { + MediaSelectorFile mediaFile = new MediaSelectorFile(); + mediaFile.fileName = file.getName(); + mediaFile.filePath = file.getAbsolutePath(); + mediaFile.fileSize = (int) file.length(); + mediaFile.width = FileUtils.getFileWidth(file.getAbsolutePath()); + mediaFile.height = FileUtils.getFileHeight(file.getAbsolutePath()); + mediaFile.folderName = FileUtils.getParentFileName(file.getAbsolutePath()); + mediaFile.folderPath = FileUtils.getParentFilePath(file.getAbsolutePath()); + mediaFile.isCheck = true; + return mediaFile; + } + + public static ImageConfig thisToDefaultImageConfig(@NonNull MediaSelectorFile mediaFile) { + return ImageConfig.getDefaultConfig(mediaFile.filePath); + } + +} diff --git a/media/src/main/java/com/example/media/bean/MediaSelectorFolder.java b/media/src/main/java/com/example/media/bean/MediaSelectorFolder.java new file mode 100644 index 0000000..c61c766 --- /dev/null +++ b/media/src/main/java/com/example/media/bean/MediaSelectorFolder.java @@ -0,0 +1,75 @@ +package com.example.media.bean; + +import android.os.Parcel; +import android.os.Parcelable; +import android.support.v4.util.LruCache; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +public class MediaSelectorFolder implements Parcelable { + public String folderName; + public String folderPath; + public List fileData = new ArrayList<>(); + public boolean isCheck; + public String firstFilePath; + public boolean isAllVideo; + + public MediaSelectorFolder() { + } + + protected MediaSelectorFolder(Parcel in) { + folderName = in.readString(); + folderPath = in.readString(); + fileData = in.createTypedArrayList(MediaSelectorFile.CREATOR); + isCheck = in.readByte() != 0; + firstFilePath = in.readString(); + isAllVideo = in.readByte() != 0; + } + + public static final Creator CREATOR = new Creator() { + @Override + public MediaSelectorFolder createFromParcel(Parcel in) { + return new MediaSelectorFolder(in); + } + + @Override + public MediaSelectorFolder[] newArray(int size) { + return new MediaSelectorFolder[size]; + } + }; + + /** + * 判断文件夹的路径是否一致判断是否相等 + * + * @param obj + * @return + */ + @Override + public boolean equals(Object obj) { + if (obj == null || folderPath == null) + return false; + if (obj instanceof MediaSelectorFolder) { + MediaSelectorFolder folder = (MediaSelectorFolder) obj; + return this.folderPath.equals(folder.folderPath); + } + return super.equals(obj); + } + + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(folderName); + dest.writeString(folderPath); + dest.writeTypedList(fileData); + dest.writeByte((byte) (isCheck ? 1 : 0)); + dest.writeString(firstFilePath); + dest.writeByte((byte) (isAllVideo ? 1 : 0)); + } +} diff --git a/media/src/main/java/com/example/media/permission/IntentUtils.java b/media/src/main/java/com/example/media/permission/IntentUtils.java new file mode 100644 index 0000000..572c936 --- /dev/null +++ b/media/src/main/java/com/example/media/permission/IntentUtils.java @@ -0,0 +1,46 @@ +package com.example.media.permission; + +import android.app.Activity; +import android.content.Intent; +import android.net.Uri; +import android.provider.Settings; +import android.support.annotation.NonNull; +import android.support.v4.app.Fragment; + +/** + * 项 目 : YZBProject + * 包 名 : com.henji.yunyi.yizhibang.utils + * 类 名 : IntentUtils + * 作 者 : 胡庆岭 + * 时 间 : 2018/1/9 0009 下午 4:03 + * 描 述 : ${TODO}意图工具类 + * + * @author : + */ + +public class IntentUtils { + public static final int OPEN_APPLY_CENTER_CODE = 5501; + + /** + * Activity打开应用中心 + * + * @param activity 页面 + */ + public static void openActivityApplyCenter(@NonNull Activity activity) { + Uri packageURI = Uri.parse("package:" + activity.getPackageName()); + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, packageURI); + activity.startActivityForResult(intent, OPEN_APPLY_CENTER_CODE); + } + + /** + * fragemnt打开应用中心 + * + * @param fragment fragment + * @param activity activity + */ + public static void openFragmentApplyCenter(@NonNull Fragment fragment, @NonNull Activity activity) { + Uri packageURI = Uri.parse("package:" + activity.getPackageName()); + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, packageURI); + fragment.startActivityForResult(intent, OPEN_APPLY_CENTER_CODE); + } +} diff --git a/media/src/main/java/com/example/media/permission/PermissionActivity.java b/media/src/main/java/com/example/media/permission/PermissionActivity.java new file mode 100644 index 0000000..86892df --- /dev/null +++ b/media/src/main/java/com/example/media/permission/PermissionActivity.java @@ -0,0 +1,189 @@ +package com.example.media.permission; + +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.ActivityCompat; +import android.support.v7.app.AlertDialog; +import android.support.v7.app.AppCompatActivity; +import android.util.Log; +import android.view.View; +import android.widget.Button; + + +import com.example.media.permission.imp.OnPermissionsResult; +import com.trello.rxlifecycle2.components.support.RxAppCompatActivity; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * 项 目 : PermissionUtils + * 包 名 : com.baixiaohu.permissionutils + * 类 名 : PermissionActivity + * 作 者 : 胡庆岭 + * 时 间 : 2018/1/11 0011 下午 12:05 + * 描 述 : ${TODO} + * + * @author : + */ + +public class PermissionActivity extends RxAppCompatActivity { + private AlertDialog mForbidDialog; + private static final int REQUEST_CODE = 100; + private List mAllowList = new ArrayList<>(); + private List mNoAllowList = new ArrayList<>(); + private List mForbidList = new ArrayList<>(); + private OnPermissionsResult mOnPermissionsResult; + private String[] mPermissions; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + + protected void requestPermission(@NonNull OnPermissionsResult onPermissionsResult, @NonNull String... permissions) { + this.mPermissions = permissions; + this.mOnPermissionsResult = onPermissionsResult; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + List requestList = new ArrayList<>(); + for (String permission : permissions) { + if (ActivityCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) { + requestList.add(permission); + } + } + if (requestList.size() > 0) { + ActivityCompat.requestPermissions(this, permissions, REQUEST_CODE); + } else { + if (mOnPermissionsResult != null ) { + mOnPermissionsResult.onAllow(Arrays.asList(permissions)); + } + } + } else { + mOnPermissionsResult.onAllow(Arrays.asList(permissions)); + } + + + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + switch (requestCode) { + case REQUEST_CODE: + if (permissions.length == grantResults.length) { + clearPermission(); + + for (int i = 0; i < grantResults.length; i++) { + + if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { + mAllowList.add(permissions[i]); + } else { + Log.w("onRequemt--", ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[i]) + ""); + if (ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[i])) { + mNoAllowList.add(permissions[i]); + } else { + mForbidList.add(permissions[i]); + } + } + } + Log.w("onRequest--", permissions.length + "--" + grantResults.length + + "--" + mAllowList.size() + "--" + mNoAllowList.size() + "--" + mForbidList.size()); + if (mAllowList.size() == permissions.length) { + if (mOnPermissionsResult != null) { + //全部同意 + mOnPermissionsResult.onAllow(mAllowList); + } + + } else { + if (mForbidList.size() > 0) { + if (mOnPermissionsResult != null) { + //全部永久禁止或者部分永久禁止 + mOnPermissionsResult.onForbid(mForbidList); + } + } else { + if (mOnPermissionsResult != null) { + //全部拒绝 + mOnPermissionsResult.onNoAllow(mNoAllowList); + } + } + } + + } + break; + default: + break; + } + } + + private void clearPermission() { + mAllowList.clear(); + mNoAllowList.clear(); + mForbidList.clear(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + clearPermission(); + } + + protected void showForbidPermissionDialog() { + if (mForbidDialog == null) { + mForbidDialog = new AlertDialog.Builder(this).setTitle("权限被禁止") + .setMessage("需要获取权限,否则无法正常使用功能;设置路径:设置-应用-权限") + .setPositiveButton("确定", null) + .setNegativeButton("取消", null) + .setCancelable(false).create(); + mForbidDialog.setOnShowListener(new DialogInterface.OnShowListener() { + @Override + public void onShow(DialogInterface dialog) { + Button positionButton = mForbidDialog.getButton(AlertDialog.BUTTON_POSITIVE); + Button negativeButton = mForbidDialog.getButton(AlertDialog.BUTTON_NEGATIVE); + positionButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + IntentUtils.openActivityApplyCenter(PermissionActivity.this); + + } + }); + negativeButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + mForbidDialog.dismiss(); + finish(); + } + }); + + } + }); + mForbidDialog.show(); + } else if (!mForbidDialog.isShowing()) { + mForbidDialog.show(); + } + } + + protected void dismissForbidPermissionDialog() { + if (mForbidDialog != null && mForbidDialog.isShowing()) { + mForbidDialog.dismiss(); + } + } + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == IntentUtils.OPEN_APPLY_CENTER_CODE && resultCode == 0) { + if (mPermissions != null && mPermissions.length > 0 && mOnPermissionsResult != null) { + requestPermission(mOnPermissionsResult, mPermissions); + dismissForbidPermissionDialog(); + // getActivity().recreate(); + } + } + } +} diff --git a/media/src/main/java/com/example/media/permission/PermissionFragment.java b/media/src/main/java/com/example/media/permission/PermissionFragment.java new file mode 100644 index 0000000..76044d8 --- /dev/null +++ b/media/src/main/java/com/example/media/permission/PermissionFragment.java @@ -0,0 +1,185 @@ +package com.example.media.permission; + +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Build; +import android.support.annotation.NonNull; +import android.support.v4.app.ActivityCompat; +import android.support.v4.app.Fragment; +import android.support.v7.app.AlertDialog; +import android.util.Log; +import android.view.View; +import android.widget.Button; + + +import com.example.media.permission.imp.OnPermissionsResult; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * 项 目 : PermissionUtils + * 包 名 : com.baixiaohu.permission + * 类 名 : PermissionFragment + * 作 者 : 胡庆岭 + * 时 间 : 2018/1/15 0015 上午 9:51 + * 描 述 : ${TODO} + * + * @author : + */ + +public class PermissionFragment extends Fragment { + private static final int REQUEST_CODE = 200; + private static List mAllowList = new ArrayList<>(); + private static List mNoAllowList = new ArrayList<>(); + private static List mForbidList = new ArrayList<>(); + private OnPermissionsResult mOnPermissionsResult; + private AlertDialog mForbidDialog; + private String[] mPermissions; + + @Override + public void onResume() { + super.onResume(); + } + + protected void requestPermission(@NonNull OnPermissionsResult onPermissionsResult, @NonNull String... permissions) { + this.mPermissions = permissions; + this.mOnPermissionsResult = onPermissionsResult; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + List requestList = new ArrayList<>(); + for (String permission : permissions) { + if (ActivityCompat.checkSelfPermission(getActivity(), permission) != PackageManager.PERMISSION_GRANTED) { + requestList.add(permission); + } + } + if (requestList.size() > 0) { + this.requestPermissions(permissions, REQUEST_CODE); + } else { + if (mOnPermissionsResult != null) { + mOnPermissionsResult.onAllow(Arrays.asList(permissions)); + } + } + } else { + mOnPermissionsResult.onAllow(Arrays.asList(permissions)); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + switch (requestCode) { + case REQUEST_CODE: + if (permissions.length == grantResults.length) { + clearPermission(); + for (int i = 0; i < grantResults.length; i++) { + + if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { + mAllowList.add(permissions[i]); + } else { + Log.w("onRequemt--", ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), permissions[i]) + ""); + if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), permissions[i])) { + mNoAllowList.add(permissions[i]); + } else { + mForbidList.add(permissions[i]); + } + } + } + Log.w("onRequest--", permissions.length + "--" + grantResults.length + + "--" + mAllowList.size() + "--" + mNoAllowList.size() + "--" + mForbidList.size()); + if (mAllowList.size() == permissions.length) { + if (mOnPermissionsResult != null) { + //全部同意 + mOnPermissionsResult.onAllow(mAllowList); + } + + } else { + if (mForbidList.size() > 0) { + if (mOnPermissionsResult != null) { + //全部永久禁止或者部分永久禁止 + mOnPermissionsResult.onForbid(mForbidList); + } + } else { + if (mOnPermissionsResult != null) { + //全部拒绝 + mOnPermissionsResult.onNoAllow(mNoAllowList); + } + } + } + } + break; + default: + break; + } + } + + private void clearPermission() { + mAllowList.clear(); + mNoAllowList.clear(); + mForbidList.clear(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + clearPermission(); + } + + protected void showForbidPermissionDialog() { + if (mForbidDialog == null) { + mForbidDialog = new AlertDialog.Builder(getActivity()).setTitle( "权限被禁止") + .setMessage("需要获取权限,否则无法正常使用功能;设置路径:设置-应用-权限") + .setPositiveButton("确定", null) + .setNegativeButton("取消", null) + .setCancelable(false).create(); + mForbidDialog.setOnShowListener(new DialogInterface.OnShowListener() { + @Override + public void onShow(DialogInterface dialog) { + Button positionButton = mForbidDialog.getButton(AlertDialog.BUTTON_POSITIVE); + Button negativeButton = mForbidDialog.getButton(AlertDialog.BUTTON_NEGATIVE); + positionButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + IntentUtils.openFragmentApplyCenter(PermissionFragment.this, getActivity()); + + } + }); + negativeButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + mForbidDialog.dismiss(); + getActivity().finish(); + } + }); + + } + }); + mForbidDialog.show(); + } else if (!mForbidDialog.isShowing()) { + mForbidDialog.show(); + } + + } + + + protected void dismissForbidPermissionDialog() { + if (mForbidDialog != null && mForbidDialog.isShowing()) { + mForbidDialog.dismiss(); + } + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + Log.w("FragmentResult--", requestCode + "--" + resultCode); + if (requestCode == IntentUtils.OPEN_APPLY_CENTER_CODE && resultCode == 0) { + if (mPermissions != null && mPermissions.length > 0 && mOnPermissionsResult != null) { + requestPermission(mOnPermissionsResult, mPermissions); + dismissForbidPermissionDialog(); + // getActivity().recreate(); + } + } + } +} diff --git a/media/src/main/java/com/example/media/permission/imp/OnPermissionsResult.java b/media/src/main/java/com/example/media/permission/imp/OnPermissionsResult.java new file mode 100644 index 0000000..d8db02a --- /dev/null +++ b/media/src/main/java/com/example/media/permission/imp/OnPermissionsResult.java @@ -0,0 +1,23 @@ +package com.example.media.permission.imp; + +import java.util.List; + +/** + * 项 目 : PermissionUtils + * 包 名 : com.baixiaohu.permission.imp + * 类 名 : OnPermissionsResult + * 作 者 : 胡庆岭 + * 时 间 : 2018/1/11 0011 下午 3:07 + * 描 述 : ${TODO} + * + * @author : + */ + +public interface OnPermissionsResult { + void onAllow(List allowPermissions); + + void onNoAllow(List noAllowPermissions); + + void onForbid(List noForbidPermissions); + +} diff --git a/media/src/main/java/com/example/media/provider/MediaProvider.java b/media/src/main/java/com/example/media/provider/MediaProvider.java new file mode 100644 index 0000000..589fc0e --- /dev/null +++ b/media/src/main/java/com/example/media/provider/MediaProvider.java @@ -0,0 +1,17 @@ +package com.example.media.provider; + +import android.support.v4.content.FileProvider; + +/** + * 项 目 : ImageCompress + * 包 名 : com.baixiaohu.imagecompress.provider + * 类 名 : MediaProvider + * 作 者 : 胡小白 + * 时 间 : 2018/1/31 0031 上午 10:33 + * 描 述 : ${TODO} + * + * @author : + */ + +public class MediaProvider extends FileProvider { +} diff --git a/media/src/main/java/com/example/media/resolver/ActivityManger.java b/media/src/main/java/com/example/media/resolver/ActivityManger.java new file mode 100644 index 0000000..4cf0c23 --- /dev/null +++ b/media/src/main/java/com/example/media/resolver/ActivityManger.java @@ -0,0 +1,60 @@ +package com.example.media.resolver; + +import android.app.Activity; +import android.support.annotation.NonNull; +import android.support.v4.util.SparseArrayCompat; + +import java.lang.ref.SoftReference; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +public class ActivityManger { + private static ActivityManger mManger; + private Map> mMap; + + private ActivityManger() { + mMap = new HashMap<>(); + } + + public static ActivityManger get() { + synchronized (ActivityManger.class) { + if (mManger == null) { + synchronized (ActivityManger.class) { + mManger = new ActivityManger(); + } + } + } + return mManger; + } + + public void addActivity(@NonNull Activity activity) { + mMap.put(activity.getClass().getSimpleName(), new SoftReference<>(activity)); + } + + public void removeActivity(@NonNull String key) { + if (mMap.size() > 0) { + SoftReference softReference = mMap.get(key); + if (softReference != null && softReference.get() != null && !softReference.get().isFinishing()) { + softReference.get().finish(); + } + mMap.remove(key); + } + } + + public void clearActivity() { + if (mMap.size() > 0) { + Set>> entrySet = mMap.entrySet(); + Iterator>> iterator = entrySet.iterator(); + while (iterator.hasNext()) { + Map.Entry> next = iterator.next(); + if (next.getValue() != null && next.getValue().get() != null) { + next.getValue().get().finish(); + } + iterator.remove(); + } + } + } + +} diff --git a/media/src/main/java/com/example/media/resolver/Contast.java b/media/src/main/java/com/example/media/resolver/Contast.java new file mode 100644 index 0000000..a7009a1 --- /dev/null +++ b/media/src/main/java/com/example/media/resolver/Contast.java @@ -0,0 +1,21 @@ +package com.example.media.resolver; + +public interface Contast { + String KEY_PREVIEW_DATA_MEDIA = "key_preview_data_media"; + String KEY_PREVIEW_CHECK_MEDIA = "key_preview_check_media"; + String KEY_PREVIEW_POSITION = "key_preview_position"; + String KEY_CLEAR_MEDIA_DATA = "key_clear_media_data"; + int REQUEST_CODE_MEDIA_TO_PREVIEW = 101; + int MAX_CHOOSE_MEDIA = 9; + String KEY_OPEN_MEDIA = "key_open_media"; + + String KEY_REQUEST_MEDIA_DATA = "key_request_media_data"; + int CODE_REQUEST_MEDIA = 1011; + int CODE_RESULT_MEDIA = 1012; + int CODE_REQUEST_PRIVIEW_VIDEO = 1013; + String ALL_FILE = "全部文件"; + String ALL_VIDEO = "全部视频"; + int REQUEST_CAMERA_CODE = 2000; + + +} diff --git a/media/src/main/java/com/example/media/resolver/ILoadMediaResult.java b/media/src/main/java/com/example/media/resolver/ILoadMediaResult.java new file mode 100644 index 0000000..e1b9b36 --- /dev/null +++ b/media/src/main/java/com/example/media/resolver/ILoadMediaResult.java @@ -0,0 +1,9 @@ +package com.example.media.resolver; + +import com.example.media.bean.MediaSelectorFolder; + +import java.util.List; + +public interface ILoadMediaResult { + void mediaResult(List data); +} diff --git a/media/src/main/java/com/example/media/resolver/MediaHelper.java b/media/src/main/java/com/example/media/resolver/MediaHelper.java new file mode 100644 index 0000000..123118a --- /dev/null +++ b/media/src/main/java/com/example/media/resolver/MediaHelper.java @@ -0,0 +1,148 @@ +package com.example.media.resolver; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.database.Cursor; +import android.net.Uri; +import android.os.Build; +import android.provider.MediaStore; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.TextUtils; +import android.util.Log; +import android.widget.Toast; + +import com.example.media.bean.MediaSelectorFile; +import com.example.media.bean.MediaSelectorFolder; +import com.example.media.utils.FileUtils; + +import java.util.ArrayList; +import java.util.List; + +public class MediaHelper { + private static final Uri QUERY_URI = MediaStore.Files.getContentUri("external"); + //查询的内容 + @SuppressLint("InlinedApi") + private static final String[] IMAGE_PROJECTION = { + MediaStore.Files.FileColumns._ID, + MediaStore.Files.FileColumns.DATA, + MediaStore.Files.FileColumns.WIDTH, + MediaStore.Files.FileColumns.HEIGHT, + MediaStore.Files.FileColumns.SIZE, + MediaStore.Files.FileColumns.MEDIA_TYPE, + MediaStore.Files.FileColumns.DISPLAY_NAME}; + @SuppressLint("InlinedApi") + private static final String[] ALL_PROJECTION = { + MediaStore.Files.FileColumns._ID, + MediaStore.Files.FileColumns.DATA, + MediaStore.Files.FileColumns.WIDTH, + MediaStore.Files.FileColumns.HEIGHT, + MediaStore.Files.FileColumns.SIZE, + MediaStore.Files.FileColumns.MEDIA_TYPE, + MediaStore.Files.FileColumns.DISPLAY_NAME, + MediaStore.Video.Media.DURATION}; + private static final String IMAGE_SELECTION_TYPE = MediaStore.Files.FileColumns.MEDIA_TYPE + "=?" + " AND " + MediaStore.MediaColumns.SIZE + ">0"; + private static final String ALL_SELECTION_TYPE = "(" + MediaStore.Files.FileColumns.MEDIA_TYPE + "=? OR " + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?)" + + " AND " + MediaStore.MediaColumns.SIZE + ">0"; + private static final String[] IMAGE_WHERE_TYPE = new String[]{String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE)}; + private static final String[] ALL_WHERE_TYPE = new String[]{String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE), String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO)}; + private static final String SORT_ORDER = MediaStore.Files.FileColumns.DATE_MODIFIED + " desc"; + private Activity mActivity; + + public MediaHelper(@NonNull Activity activity) { + this.mActivity = activity; + } + + + public void loadMedia(boolean isShowCamera, boolean isShowVideo, @Nullable ILoadMediaResult onResult) { + + Cursor cursor = mActivity.getContentResolver().query(MediaHelper.QUERY_URI, isShowVideo ? ALL_PROJECTION : MediaHelper.IMAGE_PROJECTION, isShowVideo ? ALL_SELECTION_TYPE : MediaHelper.IMAGE_SELECTION_TYPE, isShowVideo ? ALL_WHERE_TYPE : MediaHelper.IMAGE_WHERE_TYPE, SORT_ORDER); + if (cursor != null && !cursor.isClosed() && cursor.getCount() > 0) { + //所有的图片 + List mAllFileData = new ArrayList<>(); + + //所有文件夹 + List folderData = new ArrayList<>(); + List mVideoFileData = new ArrayList<>(); + + while (cursor.moveToNext()) { + MediaSelectorFile mediaFile = new MediaSelectorFile(); + mediaFile.fileName = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DISPLAY_NAME)); + + mediaFile.filePath = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DATA)); + if (TextUtils.isEmpty(mediaFile.fileName) || TextUtils.isEmpty(mediaFile.filePath) + || TextUtils.getTrimmedLength(mediaFile.fileName) == 0 || TextUtils.getTrimmedLength(mediaFile.filePath) == 0 || mediaFile.fileName.endsWith(".gif")) { + continue; + } + mediaFile.fileSize = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.SIZE)); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + mediaFile.width = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.WIDTH)); + mediaFile.height = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.HEIGHT)); + } + if (FileUtils.existsFile(mediaFile.filePath)) { + mediaFile.folderName = FileUtils.getParentFileName(mediaFile.filePath); + mediaFile.folderPath = FileUtils.getParentFilePath(mediaFile.filePath); + } else { + continue; + } + mediaFile.isVideo = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.MEDIA_TYPE)) == MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO; + if (mediaFile.isVideo) { + mediaFile.videoDuration = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION)); + if (mediaFile.videoDuration >= 60 * 60 * 1000 || mediaFile.videoDuration < 1000) { + continue; + } + mVideoFileData.add(mediaFile); + } + + MediaSelectorFolder mediaFolder = new MediaSelectorFolder(); + mediaFolder.folderPath = mediaFile.folderPath; + //首先判断该文件的父文件夹有没有在集合中?有的话直接把文件加入对应的文件夹:没有就新建一个文件夹再添加进去 + if (folderData.size() > 0 && folderData.contains(mediaFolder) && folderData.indexOf(mediaFolder) >= 0) { + folderData.get(folderData.indexOf(mediaFolder)).fileData.add(mediaFile); + } else { + mediaFolder.folderName = mediaFile.folderName; + mediaFolder.fileData.add(mediaFile); + mediaFolder.firstFilePath = mediaFile.filePath; + folderData.add(mediaFolder); + } + mAllFileData.add(mediaFile); + + } + cursor.close(); + if (mAllFileData.size() > 0) { + if (isShowCamera) { + MediaSelectorFile cameraMediaFile = new MediaSelectorFile(); + cameraMediaFile.isShowCamera = true; + mAllFileData.add(0, cameraMediaFile); + } + + MediaSelectorFolder allMediaFolder = new MediaSelectorFolder(); + allMediaFolder.folderPath = Contast.ALL_FILE; + allMediaFolder.folderName = Contast.ALL_FILE; + allMediaFolder.firstFilePath = isShowCamera ? mAllFileData.get(1).filePath : mAllFileData.get(0).filePath; + allMediaFolder.fileData.addAll(mAllFileData); + allMediaFolder.isCheck = true; + folderData.add(0, allMediaFolder); + //增加视频目录 + if (mVideoFileData.size() > 0) { + MediaSelectorFolder videoMediaFolder = new MediaSelectorFolder(); + videoMediaFolder.folderPath = Contast.ALL_VIDEO; + videoMediaFolder.folderName = Contast.ALL_VIDEO; + videoMediaFolder.firstFilePath = mVideoFileData.get(0).filePath; + videoMediaFolder.fileData.addAll(mVideoFileData); + videoMediaFolder.isAllVideo = true; + folderData.add(folderData.indexOf(allMediaFolder) + 1, videoMediaFolder); + } + if (onResult != null && folderData.size() > 0) { + onResult.mediaResult(folderData); + } + } + + } else { + Toast.makeText(mActivity, "没有文件", Toast.LENGTH_SHORT).show(); + } + + } + + +} diff --git a/media/src/main/java/com/example/media/utils/DateUtils.java b/media/src/main/java/com/example/media/utils/DateUtils.java new file mode 100644 index 0000000..06e833c --- /dev/null +++ b/media/src/main/java/com/example/media/utils/DateUtils.java @@ -0,0 +1,26 @@ +package com.example.media.utils; + +public class DateUtils { + public static String videoDuration(long videoDuration) { + StringBuilder sb = new StringBuilder(); + if (videoDuration >= 1000) { + int second = (int) (videoDuration / 1000); + if (second / 60 >= 1) { + int minute = second / 60; + int remainderSecond = second % 60; + sb.append(minute).append(remainderSecond >= 10 ? ":" + remainderSecond : ":0" + remainderSecond); + } else { + if (second >= 10) { + sb.append("0:").append(second); + } else { + sb.append("0:0").append(second); + } + } + + } else { + sb.append("0:01"); + } + return sb.toString(); + + } +} diff --git a/media/src/main/java/com/example/media/utils/FileUtils.java b/media/src/main/java/com/example/media/utils/FileUtils.java new file mode 100644 index 0000000..1afbb69 --- /dev/null +++ b/media/src/main/java/com/example/media/utils/FileUtils.java @@ -0,0 +1,140 @@ +package com.example.media.utils; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.os.Build; +import android.os.Environment; +import android.support.annotation.NonNull; +import android.support.v4.content.FileProvider; + +import com.example.media.weight.MediaScanner; + +import java.io.File; +import java.util.List; + +/** + * 文件工具类 + */ +public class FileUtils { + + public static final String FILE_DIRECTOR_NAME = "MediaSelector"; + + /** + * 获取父文件夹名字 + * + * @param filePath + * @return + * @throws Exception + */ + public static String getParentFileName(@NonNull String filePath) { + return getParentFile(filePath).getName(); + } + + /** + * 获取父文件夹绝对路径 + * + * @param filePath + * @return + * @throws Exception + */ + public static String getParentFilePath(@NonNull String filePath) { + return getParentFile(filePath).getAbsolutePath(); + } + + private static File getParentFile(@NonNull String filePath) { + File file = new File(filePath); + if (file.exists() && file.isFile()) { + return file.getParentFile(); + } + throw new NullPointerException("file must exists or isFile"); + } + + public static boolean existsFile(@NonNull String filePath) { + File file = new File(filePath); + if (file.exists() && file.isFile()) + return true; + return false; + } + + public static File outCameraFileDirectory(Context context) { + String storageState = Environment.getExternalStorageState(); + File rootFile = storageState.equals(Environment.MEDIA_MOUNTED) ? Environment.getExternalStorageDirectory() : context.getCacheDir(); + rootFile = new File(rootFile.getAbsolutePath(), FILE_DIRECTOR_NAME.concat("/Camera")); + if (!rootFile.exists() || !rootFile.isDirectory()) { + rootFile.mkdirs(); + } + return rootFile; + } + + + public static File outFileDirectory(Context context, String folderName) { + String storageState = Environment.getExternalStorageState(); + File rootFile = storageState.equals(Environment.MEDIA_MOUNTED) ? Environment.getExternalStorageDirectory() : context.getCacheDir(); + rootFile = new File(rootFile.getAbsolutePath(), FILE_DIRECTOR_NAME.concat("/").concat(folderName)); + if (!rootFile.exists() || !rootFile.isDirectory()) { + rootFile.mkdirs(); + } + return rootFile; + } + + public static File resultImageFile(Context context) { + return new File(outCameraFileDirectory(context).getAbsolutePath(), "hxb" + System.currentTimeMillis() + ".jpg"); + } + + public static File resultImageFile(Context context, String folderName) { + return new File(outFileDirectory(context, folderName).getAbsolutePath(), "crop" + System.currentTimeMillis() + ".jpg"); + } + + public static Uri fileToUri(@NonNull Context context, @NonNull File file, @NonNull Intent intent) { + Uri uri; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + String authority = context.getPackageName() + ".provider"; + uri = FileProvider.getUriForFile(context, authority, file); + List resolveInfoData = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); + if (resolveInfoData != null && resolveInfoData.size() > 0) + for (ResolveInfo resolveInfo : resolveInfoData) { + String packageName = resolveInfo.activityInfo.packageName; + context.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + } + } else { + uri = Uri.fromFile(file); + } + return uri; + } + + public static void scanImage(@NonNull Context context, @NonNull File file) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + MediaScanner ms = new MediaScanner(context, file); + ms.refresh(); + } else { + Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); + intent.setData(Uri.fromFile(file)); + context.sendBroadcast(intent); + } + } + + public static int getFileWidth(@NonNull String path) { + return getBitmapOptions(path).outWidth; + } + + public static int getFileHeight(@NonNull String path) { + return getBitmapOptions(path).outHeight; + } + + private static BitmapFactory.Options getBitmapOptions(@NonNull String path) { + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + options.inScaled = false; + options.inMutable = true; + Bitmap bitmap = BitmapFactory.decodeFile(path, options); + if (bitmap != null && !bitmap.isRecycled()) { + bitmap.recycle(); + } + return options; + } +} diff --git a/media/src/main/java/com/example/media/utils/GlideUtils.java b/media/src/main/java/com/example/media/utils/GlideUtils.java new file mode 100644 index 0000000..6efee8f --- /dev/null +++ b/media/src/main/java/com/example/media/utils/GlideUtils.java @@ -0,0 +1,40 @@ +package com.example.media.utils; + +import android.content.Context; +import android.support.annotation.DrawableRes; +import android.support.annotation.NonNull; +import android.widget.ImageView; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.GlideBuilder; +import com.bumptech.glide.load.engine.DiskCacheStrategy; +import com.bumptech.glide.load.engine.cache.DiskLruCacheFactory; +import com.bumptech.glide.module.AppGlideModule; +import com.bumptech.glide.request.RequestOptions; +import com.bumptech.glide.request.target.Target; +import com.example.media.R; + +public class GlideUtils { + public static void loadImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView) { + RequestOptions options = new RequestOptions().centerCrop().placeholder(R.mipmap.icon_image_background).error(R.mipmap.icon_image_background) + .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC); + Glide.with(context).asBitmap().apply(options).load(url).into(imageView); + } + + public static void loadImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView, boolean isCenterCrop) { + RequestOptions options = new RequestOptions().placeholder(R.mipmap.icon_image_background) + .error(R.mipmap.icon_image_background).diskCacheStrategy(DiskCacheStrategy.AUTOMATIC); + if (isCenterCrop) { + options = options.centerCrop(); + } else { + options = options.centerInside(); + } + Glide.with(context).asBitmap().apply(options).load(url).into(imageView); + } + + public static void loadImage(@NonNull Context context, @DrawableRes int resId, @NonNull ImageView imageView) { + RequestOptions options = new RequestOptions().centerInside().placeholder(R.mipmap.icon_image_background).error(R.mipmap.icon_image_background).diskCacheStrategy(DiskCacheStrategy.AUTOMATIC); + Glide.with(context).asBitmap().apply(options).load(resId).into(imageView); + } + +} diff --git a/media/src/main/java/com/example/media/utils/ScreenUtils.java b/media/src/main/java/com/example/media/utils/ScreenUtils.java new file mode 100644 index 0000000..7cfb29a --- /dev/null +++ b/media/src/main/java/com/example/media/utils/ScreenUtils.java @@ -0,0 +1,115 @@ +package com.example.media.utils; + +import android.app.Activity; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Color; +import android.graphics.Point; +import android.os.Build; +import android.support.annotation.NonNull; +import android.view.Display; +import android.view.KeyCharacterMap; +import android.view.KeyEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.view.WindowManager; + +public class ScreenUtils { + + + public static int screenWidth(@NonNull Context context) { + return context.getResources().getDisplayMetrics().widthPixels; + } + + public static int screenHeight(@NonNull Context context) { + return context.getResources().getDisplayMetrics().heightPixels; + } + + public static int dp2px(Context context, float dpValue) { + float scale = context.getResources().getDisplayMetrics().density; + return (int) (dpValue * scale + 0.5F); + } + + public static int px2dp(Context context, float pxValue) { + float scale = context.getResources().getDisplayMetrics().density; + return (int) (pxValue / scale + 0.5F); + } + + public static void setDefaultRootViewSize(@NonNull Context context, @NonNull ViewGroup rootView) { + ViewGroup.LayoutParams rootParams = rootView.getLayoutParams(); + rootParams.width = -1; + rootParams.height = dp2px(context, 45.0F); + rootView.setLayoutParams(rootParams); + } + + public static int getStatuWindowsHeight(@NonNull Context context) { + return context.getResources().getDimensionPixelSize(context.getResources().getIdentifier("status_bar_height", "dimen", "android")); + } + /** + * 判断导航栏是否显示 + * + * @param context 上下文 + * @return 导航栏是否显示 + */ + public static boolean isShowDeviceHasNavigationBar(@NonNull Context context) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + if (windowManager == null) { + return false; + } + Display display = windowManager.getDefaultDisplay(); + Point size = new Point(); + Point realSize = new Point(); + display.getSize(size); + display.getRealSize(realSize); + return realSize.y != size.y; + } else { + boolean menu = ViewConfiguration.get(context).hasPermanentMenuKey(); + boolean back = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK); + return !menu && !back; + } + } + + /** + * 隐藏导航栏 + * + * @param activity 显示界面 + */ + public static void hideTransparentNavigation(Activity activity) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + View decorView = activity.getWindow().getDecorView(); + decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_IMMERSIVE + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); + activity.getWindow().setNavigationBarColor(Color.TRANSPARENT); + } + } + + /** + * 显示导航栏 + * + * @param activity 显示界面 + */ + public static void showTransparentNavigation(Activity activity) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + View decorView = activity.getWindow().getDecorView(); + decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); + } + + } + + /** + * 判断导航栏高度 + * + * @param context 上下文 + * @return 导航栏高度 + */ + public static int getNavigationHeight(@NonNull Context context) { + Resources resources = context.getResources(); + int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android"); + return resources.getDimensionPixelSize(resourceId); + } +} diff --git a/media/src/main/java/com/example/media/weight/DialogHelper.java b/media/src/main/java/com/example/media/weight/DialogHelper.java new file mode 100644 index 0000000..5151b0f --- /dev/null +++ b/media/src/main/java/com/example/media/weight/DialogHelper.java @@ -0,0 +1,34 @@ +package com.example.media.weight; + +import android.content.Context; +import android.content.DialogInterface; +import android.support.annotation.NonNull; +import android.support.v7.app.AlertDialog; + +import com.example.media.R; + +/** + * 项 目 : MediaSelector + * 包 名 : com.example.media.weight + * 类 名 : ${CLASS_NAME} + * 作 者 : 胡庆岭 + * 时 间 : 2018/11/10 + * 描 述 : ${TODO} + * + * @author : + */ +public class DialogHelper { + private DialogHelper() { + } + + public static DialogHelper with() { + return new DialogHelper(); + } + + public AlertDialog createDialog(@NonNull Context context, @NonNull String title, @NonNull String message, + @NonNull DialogInterface.OnClickListener onNegativeListener, @NonNull DialogInterface.OnClickListener onPositiveListener) { + return new AlertDialog.Builder(context).setTitle(title).setMessage(message) + .setNegativeButton(R.string.cancel, onNegativeListener).setPositiveButton(R.string.confirm, onPositiveListener) + .create(); + } +} diff --git a/media/src/main/java/com/example/media/weight/FolderWindow.java b/media/src/main/java/com/example/media/weight/FolderWindow.java new file mode 100644 index 0000000..d6befa8 --- /dev/null +++ b/media/src/main/java/com/example/media/weight/FolderWindow.java @@ -0,0 +1,152 @@ +package com.example.media.weight; + +import android.animation.Animator; +import android.animation.ObjectAnimator; +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.drawable.ColorDrawable; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.DefaultItemAnimator; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.LinearInterpolator; +import android.widget.PopupWindow; + +import com.example.item.Contast; +import com.example.media.OnRecyclerItemClickListener; +import com.example.media.R; +import com.example.media.adapter.MediaFolderAdapter; +import com.example.media.bean.MediaSelectorFolder; +import com.example.media.utils.ScreenUtils; + +import java.util.ArrayList; +import java.util.List; + +public class FolderWindow { + private List mFolderData; + private PopupWindow mPopupWindow; + private MediaFolderAdapter mFolderAdapter; + private Context mContext; + private View mViewRoot; + private View mShowView; + + public void setOnPopupItemClickListener(OnPopupItemClickListener onPopupItemClickListener) { + this.onPopupItemClickListener = onPopupItemClickListener; + } + + private OnPopupItemClickListener onPopupItemClickListener; + + public FolderWindow(@NonNull Context context, @Nullable List folderData) { + if (folderData == null) { + folderData = new ArrayList<>(); + } + this.mFolderData = folderData; + this.mContext = context; + createWindows(); + initEvent(); + } + + private void initEvent() { + mViewRoot.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + FolderWindow.this.dismissWindows(); + } + }); + mFolderAdapter.setOnRecyclerItemClickListener(new OnRecyclerItemClickListener() { + @Override + public void itemClick(@NonNull View view, int position) { + if (onPopupItemClickListener != null) { + onPopupItemClickListener.onItemClick(view, position); + } + FolderWindow.this.dismissWindows(); + } + }); + } + + public PopupWindow getFolderWindow() { + return mPopupWindow; + } + + public void dismissWindows() { + windowAnimation(false); + } + + private void createWindows() { + if (mPopupWindow == null) { + mPopupWindow = new PopupWindow(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + mPopupWindow.setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(mContext, R.color.color80000000))); + mPopupWindow.setClippingEnabled(false); + //mPopupWindow.setOutsideTouchable(true); + @SuppressLint("InflateParams") + View inflateView = LayoutInflater.from(mContext).inflate(R.layout.popup_media_view, null, false); + RecyclerView mRvFolder = inflateView.findViewById(R.id.rv_folder); + mViewRoot = inflateView.findViewById(R.id.ll_root); + mRvFolder.setLayoutManager(new LinearLayoutManager(mContext)); + mFolderAdapter = new MediaFolderAdapter(mFolderData); + mRvFolder.setItemAnimator(new DefaultItemAnimator()); + mRvFolder.setAdapter(mFolderAdapter); + mPopupWindow.setContentView(inflateView); + + + // mPopupWindow.setAnimationStyle(R.style.DialogAnimation); + + } + } + + public void showWindows(@NonNull View view) { + this.mShowView = view; + mPopupWindow.showAtLocation(view, Gravity.BOTTOM, 0, ScreenUtils.dp2px(view.getContext(), Contast.DEFAULT_VIEW_HEIGHT)); + windowAnimation(true); + } + + + public interface OnPopupItemClickListener { + void onItemClick(@NonNull View view, int position); + } + + private void windowAnimation(final boolean isOpen) { + ObjectAnimator objectAnimator; + if (isOpen) { + objectAnimator = ObjectAnimator.ofFloat(mViewRoot, "translationY", (ScreenUtils.screenHeight(mContext) - ScreenUtils.dp2px(mContext, mShowView.getHeight())), 0); + } else { + objectAnimator = ObjectAnimator.ofFloat(mViewRoot, "translationY", 0, (ScreenUtils.screenHeight(mContext) - ScreenUtils.dp2px(mContext, mShowView.getHeight()))); + } + objectAnimator.setInterpolator(new LinearInterpolator()); + objectAnimator.setDuration(600); + objectAnimator.start(); + objectAnimator.addListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animation) { + + } + + @Override + public void onAnimationEnd(Animator animation) { + if (!isOpen) { + mPopupWindow.dismiss(); + } + } + + @Override + public void onAnimationCancel(Animator animation) { + if (!isOpen) { + mPopupWindow.dismiss(); + } + } + + @Override + public void onAnimationRepeat(Animator animation) { + + } + }); + + } + +} diff --git a/media/src/main/java/com/example/media/weight/MediaScanner.java b/media/src/main/java/com/example/media/weight/MediaScanner.java new file mode 100644 index 0000000..cfee0b7 --- /dev/null +++ b/media/src/main/java/com/example/media/weight/MediaScanner.java @@ -0,0 +1,49 @@ +package com.example.media.weight; + +import android.content.Context; +import android.media.MediaScannerConnection; +import android.net.Uri; + +import java.io.File; + +/** + * 项 目 : ImageCompress + * 包 名 : com.baixiaohu.imagecompress + * 类 名 : utils.MediaScanner + * 作 者 : 胡庆岭 + * 时 间 : 2018/1/31 0031 上午 11:03 + * 描 述 : ${TODO} + * + * @author : + */ + +public class MediaScanner implements MediaScannerConnection.MediaScannerConnectionClient { + + private MediaScannerConnection mMSC; + private File mImageFile; + + @Override + public void onMediaScannerConnected() { + mMSC.scanFile(mImageFile.getAbsolutePath(), "image"); + } + + @Override + public void onScanCompleted(String s, Uri uri) { + mMSC.disconnect(); + } + + public MediaScanner(Context context, File file) { + this.mImageFile = file; + if (mMSC == null) { + mMSC = new MediaScannerConnection(context, this); + } + + } + + public void refresh() { + if (mMSC != null && !mMSC.isConnected()) { + mMSC.connect(); + } + } + +} diff --git a/media/src/main/java/com/example/media/weight/PreviewViewPager.java b/media/src/main/java/com/example/media/weight/PreviewViewPager.java new file mode 100644 index 0000000..132cd44 --- /dev/null +++ b/media/src/main/java/com/example/media/weight/PreviewViewPager.java @@ -0,0 +1,43 @@ +package com.example.media.weight; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.view.ViewPager; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.ViewGroup; + +import com.example.media.utils.ScreenUtils; + +public class PreviewViewPager extends ViewPager { + public PreviewViewPager(@NonNull Context context) { + super(context); + } + + public PreviewViewPager(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + try { + return super.dispatchTouchEvent(ev); + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + try { + return super.onTouchEvent(ev); + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } +} diff --git a/media/src/main/java/com/example/media/weight/Toasts.java b/media/src/main/java/com/example/media/weight/Toasts.java new file mode 100644 index 0000000..3160890 --- /dev/null +++ b/media/src/main/java/com/example/media/weight/Toasts.java @@ -0,0 +1,54 @@ +package com.example.media.weight; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.os.Looper; +import android.support.annotation.NonNull; +import android.support.annotation.StringRes; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.TextView; +import android.widget.Toast; + +import com.example.media.R; + +public class Toasts { + + + private Toasts() { + + } + + private static Toasts mToasts = new Toasts(); + + public static Toasts with() { + return mToasts; + } + + private Toast mToast; + + public void showToast(@NonNull Context context, @NonNull String text) { + if (mToast == null) { + mToast = Toast.makeText(context.getApplicationContext(),text, Toast.LENGTH_SHORT); + + } else { + mToast.setText(text); + mToast.setDuration(Toast.LENGTH_SHORT); + } + Log.w("showToast--", "showToast"); + mToast.show(); + } + + public synchronized void showToast(@NonNull Context context, @StringRes int text, Object... object) { + + if (mToast == null) { + mToast = Toast.makeText(context.getApplicationContext(), context.getString(text, object), Toast.LENGTH_SHORT); + } else { + mToast.setText(context.getString(text, object)); + mToast.setDuration(Toast.LENGTH_SHORT); + } + Log.w("showToast--", "showToast"); + mToast.show(); + } +} diff --git a/media/src/main/res/anim/anim_dialog_in.xml b/media/src/main/res/anim/anim_dialog_in.xml new file mode 100644 index 0000000..aba5cc0 --- /dev/null +++ b/media/src/main/res/anim/anim_dialog_in.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/media/src/main/res/anim/anim_dialog_out.xml b/media/src/main/res/anim/anim_dialog_out.xml new file mode 100644 index 0000000..54856c7 --- /dev/null +++ b/media/src/main/res/anim/anim_dialog_out.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/media/src/main/res/drawable/selector_item_image.xml b/media/src/main/res/drawable/selector_item_image.xml new file mode 100644 index 0000000..b2a1a15 --- /dev/null +++ b/media/src/main/res/drawable/selector_item_image.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/media/src/main/res/drawable/selector_item_video_status.xml b/media/src/main/res/drawable/selector_item_video_status.xml new file mode 100644 index 0000000..21fa60d --- /dev/null +++ b/media/src/main/res/drawable/selector_item_video_status.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/media/src/main/res/drawable/shape_media_check.xml b/media/src/main/res/drawable/shape_media_check.xml new file mode 100644 index 0000000..f83ed15 --- /dev/null +++ b/media/src/main/res/drawable/shape_media_check.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/media/src/main/res/drawable/shape_media_uncheck.xml b/media/src/main/res/drawable/shape_media_uncheck.xml new file mode 100644 index 0000000..9e752a8 --- /dev/null +++ b/media/src/main/res/drawable/shape_media_uncheck.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/media/src/main/res/layout/activity_media.xml b/media/src/main/res/layout/activity_media.xml new file mode 100644 index 0000000..b278baf --- /dev/null +++ b/media/src/main/res/layout/activity_media.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/media/src/main/res/layout/activity_preview.xml b/media/src/main/res/layout/activity_preview.xml new file mode 100644 index 0000000..75e18b2 --- /dev/null +++ b/media/src/main/res/layout/activity_preview.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + diff --git a/media/src/main/res/layout/item_camera_media_view.xml b/media/src/main/res/layout/item_camera_media_view.xml new file mode 100644 index 0000000..aef1fd2 --- /dev/null +++ b/media/src/main/res/layout/item_camera_media_view.xml @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/media/src/main/res/layout/item_check_media_view.xml b/media/src/main/res/layout/item_check_media_view.xml new file mode 100644 index 0000000..1a86734 --- /dev/null +++ b/media/src/main/res/layout/item_check_media_view.xml @@ -0,0 +1,22 @@ + + + + + + \ No newline at end of file diff --git a/media/src/main/res/layout/item_media_file_view.xml b/media/src/main/res/layout/item_media_file_view.xml new file mode 100644 index 0000000..bf1036c --- /dev/null +++ b/media/src/main/res/layout/item_media_file_view.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/media/src/main/res/layout/item_media_folder.xml b/media/src/main/res/layout/item_media_folder.xml new file mode 100644 index 0000000..902d512 --- /dev/null +++ b/media/src/main/res/layout/item_media_folder.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/media/src/main/res/layout/item_video_play_view.xml b/media/src/main/res/layout/item_video_play_view.xml new file mode 100644 index 0000000..f0facbd --- /dev/null +++ b/media/src/main/res/layout/item_video_play_view.xml @@ -0,0 +1,21 @@ + + + + + + + + + \ No newline at end of file diff --git a/media/src/main/res/layout/popup_media_view.xml b/media/src/main/res/layout/popup_media_view.xml new file mode 100644 index 0000000..8257933 --- /dev/null +++ b/media/src/main/res/layout/popup_media_view.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/media/src/main/res/mipmap-xhdpi/icon_image_background.png b/media/src/main/res/mipmap-xhdpi/icon_image_background.png new file mode 100644 index 0000000000000000000000000000000000000000..5c4f2636ca661a4e7a9be5f5b3001e564824da8f GIT binary patch literal 763 zcmeAS@N?(olHy`uVBq!ia0vp^TR@ltNH9n&i+snxz;wvd#WAGf*4x{$#j_kl*dAws^@YL@Y)nd&rT>SKeW6_)44RXuVr_Z0>{?`3?clX4D zn>=q{{QTs8#-2}`!xmm%y;^FyuAj@at6$!C)LU*TS$cETw^`C+mlk&gsXNSGv^Oc> z|LFu>%f{yA4(blliz*90XZP*@md`g=^g7ptw2Z)SDb`oSkA7}>$(o_OCH~i?;EDXN z->tuP{Fsny0{>lI5x+ItWn#}?n7nSq`ZE?*8dILBct6fA{-oo)_vwvubL4bFxqXj( zPL0>qzcoYmM>lK9jFtR14DZi5>NBH?YwAq*ezET@PABaDTkQ;;xgsQO-}2=zYaOrY zA3ZLzW+x+0@%x1@Qp&zBvGhCsKr>*)8^#x|cOHB_bYDg&X5l9G1)JSIcmCh${qtM! zLZinS+p>O`o88k=TI9SmU}ol)>jrx}I#Pp`R*7gC_dIJo*ZeKVZ_90Orjjfv-7dM8 zIg@?1T{)6weE3DgcT=A!o5Lg9d_oV039kKLR2XonJTtZP<;#V;zn)tA=TxTjtUoJP zD&PF`>`<(W@C65EUK4a;){Exa%Z}1}xAx!5T6|yY_On;M+uHwd-+Q+DZhcw({fTz7 o%B-L3x%Ai&PE;8SWZnO>ZI5-3T=P^&4V0=qUHx3vIVCg!0968Sq5uE@ literal 0 HcmV?d00001 diff --git a/media/src/main/res/mipmap-xhdpi/icon_image_type.png b/media/src/main/res/mipmap-xhdpi/icon_image_type.png new file mode 100644 index 0000000000000000000000000000000000000000..7e36af403dab2855b58698b16ccf6f7ecebca1e3 GIT binary patch literal 191 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX3?zBp#Z3TF0X`wF|Ns9#4+C}k=9~tKvy=q+ z1v42dAc};Xq>M->CM!jz{4D<@_qkiFVSC~#-}TjBf?L;lj%|y@zb`SKi!L4rwG}Qs^Tpum*_ef*Q7~kF WrJv1io`*chVGN$GelF{r5}E+ME=Mx} literal 0 HcmV?d00001 diff --git a/media/src/main/res/mipmap-xhdpi/icon_video_pause.png b/media/src/main/res/mipmap-xhdpi/icon_video_pause.png new file mode 100644 index 0000000000000000000000000000000000000000..da1c107d30d6c288eb581e45290e86209ab42945 GIT binary patch literal 2714 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 Ue@m{MWdHyG07*qoM6N<$f;KDvyZ`_I literal 0 HcmV?d00001 diff --git a/media/src/main/res/mipmap-xhdpi/icon_video_start.png b/media/src/main/res/mipmap-xhdpi/icon_video_start.png new file mode 100644 index 0000000000000000000000000000000000000000..22702410215d10e72352865f5c9ae175530d7e2e GIT binary patch literal 3253 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 literal 0 HcmV?d00001 diff --git a/media/src/main/res/mipmap-xxhdpi/icon_camera.png b/media/src/main/res/mipmap-xxhdpi/icon_camera.png new file mode 100644 index 0000000000000000000000000000000000000000..b4f3c265c2e6f27bd43e8fe79be33c72de23c3a3 GIT binary patch literal 2754 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 BgMk15 literal 0 HcmV?d00001 diff --git a/media/src/main/res/mipmap-xxhdpi/icon_image_checked.png b/media/src/main/res/mipmap-xxhdpi/icon_image_checked.png new file mode 100644 index 0000000000000000000000000000000000000000..c3e13ff67dfb3ba2c39d7f5e6c426fa094e20abf GIT binary patch literal 1108 zcmV-a1grarP)ycCU~9;1tWwoSA=io@W+HN=iyf zT1o|23v37afYZPrPz8E{&A^IQRW2`<1N(p*z!VT=urc5g&;u+izRF=(4_pRj$R=8{ zao`xRxY+9Z(+OMzYBVQ2ZSR17pshG5?(6`b6IOWIZUU=|66C@`;4S%zkL@wAr5IV+ zI8QOcllBqVT7)!Y)%g%6) zf_$t$l<1f?)K*o;=7PmVzyxYzCB2^kI>Ja-;%@<`g!f|wiB5{|te0(CajH!#ry)K< ze=ynFLh&(DBg_EpO{quiyCdL{@cvp(LUlF_bPM&U3VC+BOKz|Zn5;WGp?N_2kc7utOgNH&oTa+jM@@Y&xA>@~jZP2PX!6J==VIl21 zOTpvF8xdV24Kub*Rfx;HzU9X`2C-Ih3hw zfCoa_mAFTNvNpm|;ESVgo!!Z(`zN{~@Y0a}o=2r@jc|l8;v-Z;IYL&jG~`xrzr^AUNwWcHe%(a9$AN_N{4SYm>l+5F$;?!F>BO4(ze`Sd7{- zzcBc5u_vfycU~BYcG|H|Y!|WrvDE<_!f&Ohp<H70S)D?IS0WLX1(2hN>KaFDq=5M5mJtRJaI#~U)EWzFzKB9JJ!Pn$+_vd$#cGP5b9rMw68nq;PU0MH4R8YgD8+F&Pq5k|w|J+ literal 0 HcmV?d00001 diff --git a/media/src/main/res/mipmap-xxhdpi/icon_image_unchecked.png b/media/src/main/res/mipmap-xxhdpi/icon_image_unchecked.png new file mode 100644 index 0000000000000000000000000000000000000000..68df95dc926bc6a8ae906f761151083adacdec9d GIT binary patch literal 1205 zcmV;m1WNmfP)C8P1e!$`g{F|gEL=<%Cyxv>=iK}5d-u&md>`D!F!%lE z-1qJ|@7{ACl$4Z|lnj*-;4p9kI0IY(=79!K2aW;<3N*w}DlllcKeNYrrJ1 zYw#||;a%Vcuui%`TkQ#O5!f?W_p?(4W`URF8+dQ~3zz{agBwaX9|OM;ci_G4d*Gcx z4Jd?Dq<`vdBp)mTP2e%Gmh#%pX5VdDOl)HnWT~oQP5lju&(3wj_Bs+SQK$fSkgToIGMqRO z%K;CwhW$ni@nrBF^rv~uFn&LV@sx}qc}ANBqj|+IZi+oL{=cOd{s;Ilui-$>DSmW- zPx6TFW-GH_QvR=?Xa2=JMl(`DUp+455xvkU((LWh9=x&;0-`aM*PT?;i9 z8EyN0Ayg#E{7HLc^n0op`!d+&xZJ1Tr*A?;T1H$X)FGNJ!T3Siay5riu zVGt}SzAT4|Xd&>_(f=o<{|frjxkx?&{#AVWB2;Kv5$Rx;!mKKABh+wCnuZ?}p+Yr7 z$a6_rX}1brpAwtxErPTGN;z{aWEL zvOsHlbnm1cTv}EPLrvU=oK@`ia&K!PpUyOpP0KWrPc9=RH{Y>%(r$Qs%0$g!aL!|} zg8LLVR!dHu3*(Bz_zF@$aZ$&eu=2F$z>ye(bnzzo=}*$004F^fdypmb9}b<6_6rgw zZ^ap+pHcjYZ5DqFjv*y8*PFsM)t8Wg59QpUioNjYPL65c^*fR9m`5s0Ew(~sZS(gM zlH4XKeo38*QMOKst+qyB1?E+xf&UY@MFzJU9145!&xQ@;eLj?rmIlQE;78muqK(Az zw)&VcHls+gTEM+}TSH!nnU1VqB}R}isUf?wBb&ds^~cR6B_$;#B_$;#uLJ)B-bXo4 TBbTB!00000NkvXXu0mjfL8~;c literal 0 HcmV?d00001 diff --git a/media/src/main/res/mipmap-xxhdpi/icon_preview_check.png b/media/src/main/res/mipmap-xxhdpi/icon_preview_check.png new file mode 100644 index 0000000000000000000000000000000000000000..2f04437225bbae3f851f0571b3e40978239461c8 GIT binary patch literal 671 zcmV;Q0$}}#P)WbH)?N+O#pmv(&_|&01yBIK%W5$_$O{b@@pV`9vFbg zqd8AkA$q!(5Plm7fXGL0S@gbT^p-^f04R@VZ21>$zX7V_8DlIV{<+5h>*GOXr$AWr z5+EjgjOKh=*&y*82w%#6w(|gO;yVw}HonsUCgM#16i{+vu|LgDcqReniJV-lj#=<8 zK&ZMF-yA^l>-Wbca&loG!EAhU0F|AV9cvfCe0+;%0A5xdZwJ9nd~*O2`ABC6ZV>Fn zw*Wv5gx^6{-&j~)cmHVmugpOMZ)EdXPT#WXpAmbbZfYLxg} zb%(ohjdXUfd^!ArZk`wmAbbKPW~n~@uvL6mVTCoA^&g(Ll+3AWFpdBK002ovPDHLk FV1mq>8MXib literal 0 HcmV?d00001 diff --git a/media/src/main/res/mipmap-xxhdpi/icon_preview_uncheck.png b/media/src/main/res/mipmap-xxhdpi/icon_preview_uncheck.png new file mode 100644 index 0000000000000000000000000000000000000000..42a2fd382f88c99cd5daec8f1af1e7ff8414de93 GIT binary patch literal 473 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEU|ito;uumf=k2ZiUWWrj*gkYy zaFi8rsy#0|5%9uxr$QeepX_f2*7;^nTBitZ&{w zVQk?Ro^EHKJ*gm(&9d5u+nxjHWg@|&{gVH`Ga@NIu!`Z}nYKy>p!qQ~9Hpgne**1! zwExs9pWJ{`@;f9gWP>-WuOS3G{K5ph`lcj9|T=~b5xu`gxt(p;*#Gp@NY zd#&GD&!tbN25FthX;<0#(Y7RZzl~+_s!a#eQXA&Gcw6_htoQgaw?$p|_3W~mxSwwX dS$xlO>DK$N9ddTxA+~B7u-yfzX$L5ENB#tB)NQCI!sNvb3 zIOVVLZsy(F5C1-}rLz9a?>BrhZ?;A`aVWM3fCvUF2mTwgCz~=jEqHq)n>pgtZ4pNK zGwS^g+g(1UCdizhk&?^PkQw_{r&1$gAN!tJ%$v;QuLP}>u#ecodO)jyuSV_6izTgY zp=N~&TPj{X?%6Y+se$zYN5!d=zttITu;}T2uH$4VYrM@=Y0tu-eL(Uxz@5N zmy^!fv3rKR%l`?YT-s{``!qBC4R&6(`)~K-8LQvxjMS6n1{-wqOI|Tet~l21tB_JA y>sGvluW>;}<>KJkH|yoEojwN+ED&MyNIccBlIdE|%|u{CF?hQAxvX + + #FF303030 + #FFEEEEEE + #FF285428 + #FF1F8F1F + #FF191814 + #80000000 + #A0000000 + diff --git a/media/src/main/res/values/strings.xml b/media/src/main/res/values/strings.xml new file mode 100644 index 0000000..3d931ab --- /dev/null +++ b/media/src/main/res/values/strings.xml @@ -0,0 +1,25 @@ + + media + 返回 + 完成 + 全部图片 + 预览 + %s张 + %s/%s + 选择 + 完成(%s/%s) + 最大选择%s张 + 提示 + 取消 + 确定 + 相机 + %s为必要权限,请允许,否则无法使用 + 储存卡 + 没有获取到照片 + 压缩图片失败 + 该视频格式不支持 + 裁剪图片失败 + 视频不支持裁剪 + 文件不存在 + + diff --git a/media/src/main/res/values/styles.xml b/media/src/main/res/values/styles.xml new file mode 100644 index 0000000..d055f4e --- /dev/null +++ b/media/src/main/res/values/styles.xml @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/media/src/main/res/xml/provider_path.xml b/media/src/main/res/xml/provider_path.xml new file mode 100644 index 0000000..78fe384 --- /dev/null +++ b/media/src/main/res/xml/provider_path.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 9230338..a7c22c0 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':app', ':compress',':matisse' +include ':app', ':compress',':media' From 51f408cee11a61fe5a2c5f0f87038bda0e017508 Mon Sep 17 00:00:00 2001 From: HuXiaobai <1203747102@qq.com> Date: Tue, 20 Nov 2018 14:07:52 +0800 Subject: [PATCH 2/3] =?UTF-8?q?2.1.0=E5=BC=80=E5=8F=91=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 10 +++++----- compress/src/main/java/utils/CompressPicker.java | 1 - 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 1e0d323..77008d6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,14 +5,14 @@ android { abortOnError false } - /* signingConfigs { + signingConfigs { release { keyAlias 'key' keyPassword '123456' storeFile file('D:/AndroidWork/ImageCompress/key.jks') storePassword '123456' } - }*/ + } defaultConfig { def versions = rootProject.ext.android compileSdkVersion versions.compileSdkVersion @@ -23,10 +23,11 @@ android { versionName versions.versionName testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" buildToolsVersion versions.buildToolsVersion + resConfigs "zh" } buildTypes { release { - // signingConfig signingConfigs.release + signingConfig signingConfigs.release minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' buildConfigField("boolean", "IS_DEBUG", "false") @@ -63,7 +64,6 @@ dependencies { implementation versions.glide implementation versions.design implementation project(':compress') - implementation files('libs/systembartint-1.0.4.jar') implementation versions.PhotoView implementation versions.multidex debugImplementation versions.leakcanaryAndroid @@ -71,7 +71,7 @@ dependencies { debugImplementation versions.leakcanarySupportFragment implementation versions.supportV4 implementation versions.rxlifecycleComponents - implementation project(':matisse') + implementation project(':media') } allprojects { repositories { diff --git a/compress/src/main/java/utils/CompressPicker.java b/compress/src/main/java/utils/CompressPicker.java index 8a794f9..746c38d 100644 --- a/compress/src/main/java/utils/CompressPicker.java +++ b/compress/src/main/java/utils/CompressPicker.java @@ -57,7 +57,6 @@ public void onHeaderDecoded(ImageDecoder decoder, ImageDecoder.ImageInfo info, I decoder.setTargetSize(imageConfig.compressWidth, imageConfig.compressHeight); decoder.setTargetSampleSize(150*1024); decoder.setMutableRequired(true); - decoder.setMemorySizePolicy(); decoder.close(); } }); From f523836c90e900d005122aa41d6a21fbc2ec8ceb Mon Sep 17 00:00:00 2001 From: HuXiaobai <1203747102@qq.com> Date: Tue, 20 Nov 2018 14:28:44 +0800 Subject: [PATCH 3/3] =?UTF-8?q?2.1.0=E5=BC=80=E5=8F=91=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 81 ----------------------------------------- app/release/output.json | 1 - 2 files changed, 82 deletions(-) delete mode 100644 app/build.gradle delete mode 100644 app/release/output.json diff --git a/app/build.gradle b/app/build.gradle deleted file mode 100644 index 77008d6..0000000 --- a/app/build.gradle +++ /dev/null @@ -1,81 +0,0 @@ -apply plugin: 'com.android.application' - -android { - lintOptions { - abortOnError false - } - - signingConfigs { - release { - keyAlias 'key' - keyPassword '123456' - storeFile file('D:/AndroidWork/ImageCompress/key.jks') - storePassword '123456' - } - } - defaultConfig { - def versions = rootProject.ext.android - compileSdkVersion versions.compileSdkVersion - applicationId "com.baixiaohu.imagecompress" - minSdkVersion versions.minSdkVersion - targetSdkVersion versions.targetSdkVersion - versionCode versions.versionCode - versionName versions.versionName - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - buildToolsVersion versions.buildToolsVersion - resConfigs "zh" - } - buildTypes { - release { - signingConfig signingConfigs.release - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - buildConfigField("boolean", "IS_DEBUG", "false") - //是否清理无用资源 - //shrinkResources true - //是否启用zipAlign压缩 - zipAlignEnabled true - pseudoLocalesEnabled true - } - /* debug{ - // signingConfig signingConfigs.release - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - buildConfigField("boolean","IS_DEBUG","true") - //是否清理无用资源 - shrinkResources true - //是否启用zipAlign压缩 - zipAlignEnabled true - pseudoLocalesEnabled true - }*/ - } -} - -dependencies { - implementation fileTree(include: ['*.jar'], dir: 'libs') - def versions = rootProject.ext.dependencies - //noinspection GradleCompatible - implementation versions.appcompatV7 - implementation versions.constraint - implementation 'com.android.support.constraint:constraint-layout:1.1.3' - testImplementation versions.junit - androidTestImplementation versions.runner - androidTestImplementation versions.espresso - implementation versions.glide - implementation versions.design - implementation project(':compress') - implementation versions.PhotoView - implementation versions.multidex - debugImplementation versions.leakcanaryAndroid - releaseImplementation versions.leakcanaryAndroidNoOp - debugImplementation versions.leakcanarySupportFragment - implementation versions.supportV4 - implementation versions.rxlifecycleComponents - implementation project(':media') -} -allprojects { - repositories { - jcenter() - maven { url "https://jitpack.io" } - } -} diff --git a/app/release/output.json b/app/release/output.json deleted file mode 100644 index 09be9c0..0000000 --- a/app/release/output.json +++ /dev/null @@ -1 +0,0 @@ -[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":1},"path":"app-release.apk","properties":{"packageId":"com.baixiaohu.imagecompress","split":"","minSdkVersion":"15"}}] \ No newline at end of file