From e00ac3bd1e508d3b46c29ad928ac880901b82589 Mon Sep 17 00:00:00 2001 From: mostafa_hashim Date: Tue, 7 Nov 2023 22:14:50 +0200 Subject: [PATCH] add crop image --- README.md | 13 +- .../gallery/presentation/main/MainActivity.kt | 1 + .../presentation/main/MainViewModel.kt | 1 + app/src/main/res/layout/activity_main.xml | 25 +- app/src/main/res/values/strings.xml | 1 + gallerylib/build.gradle | 4 +- gallerylib/src/main/AndroidManifest.xml | 16 + .../viewer/dialog/ImageViewerDialog.kt | 16 +- .../hashim/gallerylib/model/GalleryModel.kt | 1 + .../gallerylib/util/GalleryConstants.kt | 1 + .../util/HorizontalProgressWheelView.kt | 163 ++++++ .../java/hashim/gallerylib/util/functions.kt | 5 +- .../gallerylib/view/crop/CropActivity.kt | 105 ++++ .../gallerylib/view/crop/CropViewModel.kt | 171 ++++++ .../BottomSheetGalleryFragment.kt | 50 +- .../view/galleryActivity/GalleryActivity.kt | 81 ++- .../view/galleryActivity/GalleryViewModel.kt | 1 + .../view/galleryActivity/showMethod.kt | 3 + .../selected/RecyclerSelectedPagerAdapter.kt | 135 +++++ .../view/selected/SelectedActivity.kt | 174 ++++++ .../view/selected/SelectedPageFragment.kt | 109 ++++ .../view/selected/SelectedViewModel.kt | 16 + .../main/res/drawable-anydpi/crop_icon.xml | 11 + .../main/res/drawable-anydpi/rotate_icon.xml | 12 + .../src/main/res/drawable-hdpi/crop_icon.png | Bin 0 -> 369 bytes .../flip_horizontal_white_icon.png | Bin 0 -> 412 bytes .../flip_vertical_white_icon.png | Bin 0 -> 542 bytes .../main/res/drawable-hdpi/rotate_icon.png | Bin 0 -> 584 bytes .../res/drawable-hdpi/rotate_white_icon.png | Bin 0 -> 601 bytes .../src/main/res/drawable-mdpi/crop_icon.png | Bin 0 -> 168 bytes .../flip_horizontal_white_icon.png | Bin 0 -> 277 bytes .../flip_vertical_white_icon.png | Bin 0 -> 339 bytes .../main/res/drawable-mdpi/rotate_icon.png | Bin 0 -> 331 bytes .../res/drawable-mdpi/rotate_white_icon.png | Bin 0 -> 407 bytes .../src/main/res/drawable-xhdpi/crop_icon.png | Bin 0 -> 277 bytes .../flip_horizontal_white_icon.png | Bin 0 -> 547 bytes .../flip_vertical_white_icon.png | Bin 0 -> 738 bytes .../main/res/drawable-xhdpi/rotate_icon.png | Bin 0 -> 585 bytes .../res/drawable-xhdpi/rotate_white_icon.png | Bin 0 -> 778 bytes .../main/res/drawable-xxhdpi/crop_icon.png | Bin 0 -> 490 bytes .../flip_horizontal_white_icon.png | Bin 0 -> 978 bytes .../flip_vertical_white_icon.png | Bin 0 -> 1272 bytes .../main/res/drawable-xxhdpi/rotate_icon.png | Bin 0 -> 1108 bytes .../res/drawable-xxhdpi/rotate_white_icon.png | Bin 0 -> 1147 bytes .../flip_horizontal_white_icon.png | Bin 0 -> 1415 bytes .../flip_vertical_white_icon.png | Bin 0 -> 1695 bytes .../drawable-xxxhdpi/rotate_white_icon.png | Bin 0 -> 1523 bytes ...oke_white_normal_color_primary_checked.xml | 17 + .../src/main/res/layout/activity_crop.xml | 281 +++++++++ .../src/main/res/layout/activity_selected.xml | 80 +++ .../main/res/layout/item_pager_gallery.xml | 5 +- .../main/res/layout/item_pager_selected.xml | 51 ++ gallerylib/src/main/res/values-ar/strings.xml | 10 + gallerylib/src/main/res/values/colors.xml | 553 +++++++++--------- gallerylib/src/main/res/values/strings.xml | 10 + 55 files changed, 1785 insertions(+), 337 deletions(-) create mode 100644 gallerylib/src/main/java/hashim/gallerylib/util/HorizontalProgressWheelView.kt create mode 100644 gallerylib/src/main/java/hashim/gallerylib/view/crop/CropActivity.kt create mode 100644 gallerylib/src/main/java/hashim/gallerylib/view/crop/CropViewModel.kt create mode 100644 gallerylib/src/main/java/hashim/gallerylib/view/selected/RecyclerSelectedPagerAdapter.kt create mode 100644 gallerylib/src/main/java/hashim/gallerylib/view/selected/SelectedActivity.kt create mode 100644 gallerylib/src/main/java/hashim/gallerylib/view/selected/SelectedPageFragment.kt create mode 100644 gallerylib/src/main/java/hashim/gallerylib/view/selected/SelectedViewModel.kt create mode 100644 gallerylib/src/main/res/drawable-anydpi/crop_icon.xml create mode 100644 gallerylib/src/main/res/drawable-anydpi/rotate_icon.xml create mode 100644 gallerylib/src/main/res/drawable-hdpi/crop_icon.png create mode 100644 gallerylib/src/main/res/drawable-hdpi/flip_horizontal_white_icon.png create mode 100644 gallerylib/src/main/res/drawable-hdpi/flip_vertical_white_icon.png create mode 100644 gallerylib/src/main/res/drawable-hdpi/rotate_icon.png create mode 100644 gallerylib/src/main/res/drawable-hdpi/rotate_white_icon.png create mode 100644 gallerylib/src/main/res/drawable-mdpi/crop_icon.png create mode 100644 gallerylib/src/main/res/drawable-mdpi/flip_horizontal_white_icon.png create mode 100644 gallerylib/src/main/res/drawable-mdpi/flip_vertical_white_icon.png create mode 100644 gallerylib/src/main/res/drawable-mdpi/rotate_icon.png create mode 100644 gallerylib/src/main/res/drawable-mdpi/rotate_white_icon.png create mode 100644 gallerylib/src/main/res/drawable-xhdpi/crop_icon.png create mode 100644 gallerylib/src/main/res/drawable-xhdpi/flip_horizontal_white_icon.png create mode 100644 gallerylib/src/main/res/drawable-xhdpi/flip_vertical_white_icon.png create mode 100644 gallerylib/src/main/res/drawable-xhdpi/rotate_icon.png create mode 100644 gallerylib/src/main/res/drawable-xhdpi/rotate_white_icon.png create mode 100644 gallerylib/src/main/res/drawable-xxhdpi/crop_icon.png create mode 100644 gallerylib/src/main/res/drawable-xxhdpi/flip_horizontal_white_icon.png create mode 100644 gallerylib/src/main/res/drawable-xxhdpi/flip_vertical_white_icon.png create mode 100644 gallerylib/src/main/res/drawable-xxhdpi/rotate_icon.png create mode 100644 gallerylib/src/main/res/drawable-xxhdpi/rotate_white_icon.png create mode 100644 gallerylib/src/main/res/drawable-xxxhdpi/flip_horizontal_white_icon.png create mode 100644 gallerylib/src/main/res/drawable-xxxhdpi/flip_vertical_white_icon.png create mode 100644 gallerylib/src/main/res/drawable-xxxhdpi/rotate_white_icon.png create mode 100644 gallerylib/src/main/res/drawable/rectangle_crop_ratio_transparent_stroke_white_normal_color_primary_checked.xml create mode 100644 gallerylib/src/main/res/layout/activity_crop.xml create mode 100644 gallerylib/src/main/res/layout/activity_selected.xml create mode 100644 gallerylib/src/main/res/layout/item_pager_selected.xml diff --git a/README.md b/README.md index c79d4da..d34823d 100644 --- a/README.md +++ b/README.md @@ -8,19 +8,19 @@ android library for gallery images and videos, and capture camera image and vide ## Add it in your root build.gradle at the end of repositories or settings.gradle: ```groovy dependencyResolutionManagement { - repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) - repositories { - mavenCentral() - maven { url 'https://jitpack.io' } - } + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + mavenCentral() + maven { url 'https://jitpack.io' } } +} ``` #Step 2. Add the dependency ```groovy - implementation 'com.github.mostafahashim:GalleryLibrary:1.2.3' + implementation 'com.github.mostafahashim:GalleryLibrary:1.2.4' ``` # Usage @@ -31,6 +31,7 @@ fun openGallery() { GalleryLib(this).showGallery( isDialog = binding.viewModel?.isDialog?.value ?: false, + isOpenEdit = binding.viewModel?.isOpenEdit?.value ?: false, selectionType = if (binding.viewModel?.isShowImages?.value!! && binding.viewModel?.isShowVideos?.value!!) GalleryConstants.GalleryTypeImagesAndVideos else if (binding.viewModel?.isShowImages?.value!!) GalleryConstants.GalleryTypeImages else if (binding.viewModel?.isShowVideos?.value!!) GalleryConstants.GalleryTypeVideos diff --git a/app/src/main/java/hashim/gallery/presentation/main/MainActivity.kt b/app/src/main/java/hashim/gallery/presentation/main/MainActivity.kt index 349fc80..1f6d42a 100644 --- a/app/src/main/java/hashim/gallery/presentation/main/MainActivity.kt +++ b/app/src/main/java/hashim/gallery/presentation/main/MainActivity.kt @@ -75,6 +75,7 @@ class MainActivity : AppCompatActivity(), MainViewModel.Observer { GalleryLib(this).showGallery( isDialog = binding.viewModel?.isDialog?.value ?: false, + isOpenEdit = binding.viewModel?.isOpenEdit?.value ?: false, selectionType = if (binding.viewModel?.isShowImages?.value!! && binding.viewModel?.isShowVideos?.value!!) GalleryConstants.GalleryTypeImagesAndVideos else if (binding.viewModel?.isShowImages?.value!!) GalleryConstants.GalleryTypeImages else if (binding.viewModel?.isShowVideos?.value!!) GalleryConstants.GalleryTypeVideos diff --git a/app/src/main/java/hashim/gallery/presentation/main/MainViewModel.kt b/app/src/main/java/hashim/gallery/presentation/main/MainViewModel.kt index 74059cc..024656b 100644 --- a/app/src/main/java/hashim/gallery/presentation/main/MainViewModel.kt +++ b/app/src/main/java/hashim/gallery/presentation/main/MainViewModel.kt @@ -11,6 +11,7 @@ class MainViewModel : ViewModel() { var recyclerGalleryAdapter: RecyclerGalleryAdapter var isDialog = MutableLiveData(true) + var isOpenEdit = MutableLiveData(true) var isRTL = MutableLiveData(true) var isShowImages = MutableLiveData(true) var isShowVideos = MutableLiveData(true) diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index d9f69c7..6080ab3 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -18,13 +18,28 @@ android:orientation="vertical" android:padding="@dimen/padding_16"> - + android:orientation="horizontal"> + + + + + + RTL Direction LTR Direction Grid Columns + Edit after select \ No newline at end of file diff --git a/gallerylib/build.gradle b/gallerylib/build.gradle index 03ee7b7..3750374 100644 --- a/gallerylib/build.gradle +++ b/gallerylib/build.gradle @@ -78,6 +78,8 @@ dependencies { implementation 'androidx.media3:media3-exoplayer:1.1.1' implementation 'androidx.media3:media3-exoplayer-dash:1.1.1' implementation 'androidx.media3:media3-ui:1.1.1' + //crop + implementation("com.vanniktech:android-image-cropper:4.5.0") } afterEvaluate { @@ -88,7 +90,7 @@ afterEvaluate { groupId = 'com.github.mostafahashim' artifactId = 'gallery-lib' - version = '1.2.3' + version = '1.2.4' } } } diff --git a/gallerylib/src/main/AndroidManifest.xml b/gallerylib/src/main/AndroidManifest.xml index e582384..ce02245 100644 --- a/gallerylib/src/main/AndroidManifest.xml +++ b/gallerylib/src/main/AndroidManifest.xml @@ -56,6 +56,22 @@ android:theme="@style/AppTheme.NoActionBar.LightScreen" android:windowSoftInputMode="adjustResize" /> + + + + ( .setOnKeyListener { _, keyCode, event -> onDialogKeyEvent(keyCode, event) } .create() .apply { + window!!.setLayout( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + ) setOnShowListener { viewerView.open(builderData.transitionView, animateOpen) } setOnDismissListener { builderData.onDismissListener?.onDismiss() } } @@ -82,6 +88,10 @@ internal class ImageViewerDialog( private fun setupViewerView() { viewerView.apply { + layoutParams = RelativeLayout.LayoutParams( + RelativeLayout.LayoutParams.MATCH_PARENT, + RelativeLayout.LayoutParams.MATCH_PARENT + ) isZoomingAllowed = builderData.isZoomingAllowed isSwipeToDismissAllowed = builderData.isSwipeToDismissAllowed @@ -91,8 +101,10 @@ internal class ImageViewerDialog( setBackgroundColor(builderData.backgroundColor) // setImages(builderData.images, builderData.startPosition, builderData.imageLoader) - setImages(builderData.images, builderData.startPosition, builderData.imageLoader, - builderData.viewHolderLoader) + setImages( + builderData.images, builderData.startPosition, builderData.imageLoader, + builderData.viewHolderLoader + ) onPageChange = { position -> builderData.imageChangeListener?.onImageChange(position) } onDismiss = { dialog.dismiss() } diff --git a/gallerylib/src/main/java/hashim/gallerylib/model/GalleryModel.kt b/gallerylib/src/main/java/hashim/gallerylib/model/GalleryModel.kt index 116c285..898ba15 100644 --- a/gallerylib/src/main/java/hashim/gallerylib/model/GalleryModel.kt +++ b/gallerylib/src/main/java/hashim/gallerylib/model/GalleryModel.kt @@ -17,6 +17,7 @@ data class GalleryModel( var isSelected: Boolean = false, var type: String = "", var isVideo: Boolean = false, + var isReleasePlayer: Boolean = false, var albumName: String = "", var index_when_selected: Int = 0, var item_date_modified: Int = 0, diff --git a/gallerylib/src/main/java/hashim/gallerylib/util/GalleryConstants.kt b/gallerylib/src/main/java/hashim/gallerylib/util/GalleryConstants.kt index 92f4d1d..4dbf034 100644 --- a/gallerylib/src/main/java/hashim/gallerylib/util/GalleryConstants.kt +++ b/gallerylib/src/main/java/hashim/gallerylib/util/GalleryConstants.kt @@ -11,6 +11,7 @@ object GalleryConstants { const val Language = "localeLanguage" const val selected = "selected" + const val isOpenEdit = "isOpenEdit" const val maxSelectionCount = "MaxPhotosNumber" const val gridColumnsCount = "GridColumnsCount" const val showType = "showType" diff --git a/gallerylib/src/main/java/hashim/gallerylib/util/HorizontalProgressWheelView.kt b/gallerylib/src/main/java/hashim/gallerylib/util/HorizontalProgressWheelView.kt new file mode 100644 index 0000000..c5c6f8a --- /dev/null +++ b/gallerylib/src/main/java/hashim/gallerylib/util/HorizontalProgressWheelView.kt @@ -0,0 +1,163 @@ +package hashim.gallerylib.util + +import android.annotation.TargetApi +import android.content.Context +import android.graphics.Canvas +import android.graphics.Paint +import android.graphics.Rect +import android.os.Build +import android.util.AttributeSet +import android.view.MotionEvent +import android.view.View +import android.widget.SeekBar +import androidx.annotation.ColorInt +import androidx.appcompat.widget.AppCompatSeekBar +import androidx.core.content.ContextCompat +import hashim.gallerylib.R + + +class HorizontalProgressWheelView : View { + + private val mCanvasClipBounds = Rect() + + private var mScrollingListener: ScrollingListener? = null + private var mLastTouchedPosition = 0f + + private var mProgressLinePaint: Paint? = null + private var mProgressMiddleLinePaint: Paint? = null + private var mProgressLineWidth = 0 + private var mProgressLineHeight: Int = 0 + private var mProgressLineMargin = 0 + + private var mScrollStarted = false + private var mTotalScrollDistance = 0f + + private var mMiddleLineColor = 0 + + constructor(context: Context) : super(context) { + init() + } + + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { + init() + } + + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) { + init() + } + + constructor( + context: Context, + attrs: AttributeSet, + defStyleAttr: Int, + defStyleRes: Int + ) : super(context, attrs, defStyleAttr) { + init() + } + + fun setScrollingListener(scrollingListener: ScrollingListener?) { + mScrollingListener = scrollingListener + } + + fun setMiddleLineColor(@ColorInt middleLineColor: Int) { + mMiddleLineColor = middleLineColor + mProgressMiddleLinePaint!!.color = mMiddleLineColor + invalidate() + } + + override fun onTouchEvent(event: MotionEvent): Boolean { + when (event.action) { + MotionEvent.ACTION_DOWN -> mLastTouchedPosition = event.x + MotionEvent.ACTION_UP -> if (mScrollingListener != null) { + mScrollStarted = false + mScrollingListener!!.onScrollEnd() + } + + MotionEvent.ACTION_MOVE -> { + val distance = event.x - mLastTouchedPosition + if (distance != 0f) { + if (!mScrollStarted) { + mScrollStarted = true + if (mScrollingListener != null) { + mScrollingListener!!.onScrollStart() + } + } + onScrollEvent(event, distance) + } + } + } + return true + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + canvas.getClipBounds(mCanvasClipBounds) + val linesCount = mCanvasClipBounds.width() / (mProgressLineWidth + mProgressLineMargin) + val deltaX = mTotalScrollDistance % (mProgressLineMargin + mProgressLineWidth).toFloat() + for (i in 0 until linesCount) { + if (i < linesCount / 4) { + mProgressLinePaint!!.alpha = (255 * (i / (linesCount / 4).toFloat())).toInt() + } else if (i > linesCount * 3 / 4) { + mProgressLinePaint!!.alpha = + (255 * ((linesCount - i) / (linesCount / 4).toFloat())).toInt() + } else { + mProgressLinePaint!!.alpha = 255 + } + canvas.drawLine( + -deltaX + mCanvasClipBounds.left + i * (mProgressLineWidth + mProgressLineMargin), + mCanvasClipBounds.centerY() - mProgressLineHeight / 4.0f, + -deltaX + mCanvasClipBounds.left + i * (mProgressLineWidth + mProgressLineMargin), + mCanvasClipBounds.centerY() + mProgressLineHeight / 4.0f, mProgressLinePaint!! + ) + } + canvas.drawLine( + mCanvasClipBounds.centerX().toFloat(), + mCanvasClipBounds.centerY() - mProgressLineHeight / 2.0f, + mCanvasClipBounds.centerX().toFloat(), + mCanvasClipBounds.centerY() + mProgressLineHeight / 2.0f, + mProgressMiddleLinePaint!! + ) + } + + private fun onScrollEvent(event: MotionEvent, distance: Float) { + mTotalScrollDistance -= distance + postInvalidate() + mLastTouchedPosition = event.x + if (mScrollingListener != null) { + mScrollingListener!!.onScroll(-distance, mTotalScrollDistance) + } + } + + private fun init() { + mMiddleLineColor = + ContextCompat.getColor(context, R.color.colorPrimaryDark) + mProgressLineWidth = + context.resources.getDimensionPixelSize(R.dimen.padding_2) + mProgressLineHeight = + context.resources.getDimensionPixelSize(R.dimen.padding_20) + mProgressLineMargin = + context.resources.getDimensionPixelSize(R.dimen.padding_10) + mProgressLinePaint = Paint(Paint.ANTI_ALIAS_FLAG) + mProgressLinePaint!!.style = Paint.Style.STROKE + mProgressLinePaint!!.strokeWidth = mProgressLineWidth.toFloat() + mProgressLinePaint!!.color = ContextCompat.getColor(context, R.color.gray_dark) + mProgressMiddleLinePaint = Paint(mProgressLinePaint) + mProgressMiddleLinePaint!!.color = mMiddleLineColor + mProgressMiddleLinePaint!!.strokeCap = Paint.Cap.ROUND + mProgressMiddleLinePaint!!.strokeWidth = + context.resources.getDimensionPixelSize(R.dimen.padding_4) + .toFloat() + + } + + interface ScrollingListener { + fun onScrollStart() + fun onScroll(delta: Float, totalDistance: Float) + fun onScrollEnd() + } + +} \ No newline at end of file diff --git a/gallerylib/src/main/java/hashim/gallerylib/util/functions.kt b/gallerylib/src/main/java/hashim/gallerylib/util/functions.kt index 1e70cc5..4122492 100644 --- a/gallerylib/src/main/java/hashim/gallerylib/util/functions.kt +++ b/gallerylib/src/main/java/hashim/gallerylib/util/functions.kt @@ -2,8 +2,11 @@ package hashim.gallerylib.util import android.app.Activity import android.content.Context +import android.util.DisplayMetrics tailrec fun Context.activity(): Activity = when (this) { is Activity -> this else -> (this as? ContextWrapper)!!.baseContext.activity() -} \ No newline at end of file +} + +fun Int.dpToPx(displayMetrics: DisplayMetrics): Int = (this * displayMetrics.density).toInt() \ No newline at end of file diff --git a/gallerylib/src/main/java/hashim/gallerylib/view/crop/CropActivity.kt b/gallerylib/src/main/java/hashim/gallerylib/view/crop/CropActivity.kt new file mode 100644 index 0000000..81c5692 --- /dev/null +++ b/gallerylib/src/main/java/hashim/gallerylib/view/crop/CropActivity.kt @@ -0,0 +1,105 @@ +package hashim.gallerylib.view.crop + +import android.content.Intent +import android.graphics.Rect +import android.media.MediaScannerConnection +import android.net.Uri +import android.os.Build +import android.os.Bundle +import androidx.core.content.FileProvider +import androidx.core.net.toUri +import androidx.lifecycle.ViewModelProvider +import com.canhub.cropper.CropImage +import com.canhub.cropper.CropImageView +import hashim.gallerylib.R +import hashim.gallerylib.databinding.ActivityCropBinding +import hashim.gallerylib.model.GalleryModel +import hashim.gallerylib.util.DataProvider +import hashim.gallerylib.util.HorizontalProgressWheelView +import hashim.gallerylib.view.GalleryBaseActivity +import java.io.File + +class CropActivity : + GalleryBaseActivity( + R.string.gallery, false, true, true, false, + false, true, true + ), CropViewModel.Observer { + lateinit var binding: ActivityCropBinding + override fun doOnCreate(arg0: Bundle?) { + binding = putContentView(R.layout.activity_crop) as ActivityCropBinding + binding.viewModel = ViewModelProvider(this)[CropViewModel::class.java] + binding.viewModel?.observer = this + binding.lifecycleOwner = this + initializeViews() + setListener() + } + + override fun initializeViews() { + binding.viewModel?.position = intent.extras?.getInt("position", -1) ?: -1 + val galleryModels = intent.extras!!.get("GalleryModels") as ArrayList + binding.viewModel?.galleryModel = galleryModels[0] + binding.cropImageView.setImageCropOptions(binding.viewModel?.cropOptions!!) + binding.cropImageView.setImageUriAsync(binding.viewModel?.galleryModel!!.itemUrI.toUri()) + } + + override fun updateCropOption() { + binding.cropImageView.setImageCropOptions(binding.viewModel?.cropOptions!!) + } + + override fun setListener() { + binding.imgviewRotate.setOnClickListener { + binding.cropImageView.rotateImage(90) + } + + binding.cropImageView.setOnCropImageCompleteListener { view, result -> + if (result.error == null) { + val imageBitmap = + if (binding.cropImageView.cropShape == CropImageView.CropShape.OVAL) { + result.bitmap?.let(CropImage::toOvalBitmap) + } else { + result.bitmap + } +// binding.cropImageView.setImageUriAsync(result.uriContent) + if (imageBitmap == null) + return@setOnCropImageCompleteListener + val path = DataProvider().saveImage(imageBitmap, this) + val file = File(path) + MediaScannerConnection.scanFile( + this, + arrayOf(file.toString()), null + ) { _, uri -> + runOnUiThread { + val newUri = uri + ?: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + FileProvider.getUriForFile( + this, + applicationContext.packageName + ".provider", + file + ) + } else { + Uri.fromFile(file) + } + val galleryModel = + binding.viewModel?.getLastCroppedImage(this@CropActivity, newUri) + val galleryModels = ArrayList() + galleryModels.add(galleryModel!!) + val intent = Intent() + intent.putExtra("GalleryModels", galleryModels) + intent.putExtra("position", binding.viewModel?.position) + setResult(RESULT_OK, intent) + finish_activity() + } + } + } + } + } + + override fun onBackClicked() { + finish_activity() + } + + override fun finishWithSuccess() { + binding.cropImageView.croppedImageAsync() + } + +} \ No newline at end of file diff --git a/gallerylib/src/main/java/hashim/gallerylib/view/crop/CropViewModel.kt b/gallerylib/src/main/java/hashim/gallerylib/view/crop/CropViewModel.kt new file mode 100644 index 0000000..adbda0c --- /dev/null +++ b/gallerylib/src/main/java/hashim/gallerylib/view/crop/CropViewModel.kt @@ -0,0 +1,171 @@ +package hashim.gallerylib.view.crop + +import android.annotation.SuppressLint +import android.content.ContentUris +import android.content.Context +import android.net.Uri +import android.os.SystemClock +import android.provider.MediaStore +import android.widget.RadioGroup +import androidx.lifecycle.ViewModel +import com.canhub.cropper.CropImageOptions +import hashim.gallerylib.R +import hashim.gallerylib.model.GalleryModel +import hashim.gallerylib.util.GalleryConstants + +class CropViewModel : ViewModel() { + lateinit var observer: Observer + var galleryModel: GalleryModel = GalleryModel() + var position = -1 + var cropOptions: CropImageOptions? = CropImageOptions() + + fun onRadioChanged(radioGroup: RadioGroup, id: Int) { + when (id) { + R.id.radioFree -> { + cropOptions = + cropOptions?.copy(fixAspectRatio = false, aspectRatioX = 1, aspectRatioY = 1) + } + + R.id.radioOneOne -> { + cropOptions = + cropOptions?.copy(fixAspectRatio = true, aspectRatioX = 1, aspectRatioY = 1) + } + + R.id.radioTwoOne -> { + cropOptions = + cropOptions?.copy(fixAspectRatio = true, aspectRatioX = 2, aspectRatioY = 1) + } + + R.id.radioOneTwo -> { + cropOptions = + cropOptions?.copy(fixAspectRatio = true, aspectRatioX = 1, aspectRatioY = 2) + } + + R.id.radioThreeFour -> { + cropOptions = + cropOptions?.copy(fixAspectRatio = true, aspectRatioX = 3, aspectRatioY = 4) + } + + R.id.radioFourThree -> { + cropOptions = + cropOptions?.copy(fixAspectRatio = true, aspectRatioX = 4, aspectRatioY = 3) + } + + R.id.radioNineSixteen -> { + cropOptions = + cropOptions?.copy(fixAspectRatio = true, aspectRatioX = 9, aspectRatioY = 16) + } + + R.id.radioSixteenNine -> { + cropOptions = + cropOptions?.copy(fixAspectRatio = true, aspectRatioX = 16, aspectRatioY = 9) + } + + R.id.radioTwoThree -> { + cropOptions = + cropOptions?.copy(fixAspectRatio = true, aspectRatioX = 2, aspectRatioY = 3) + } + + R.id.radioThreeTwo -> { + cropOptions = + cropOptions?.copy(fixAspectRatio = true, aspectRatioX = 3, aspectRatioY = 2) + } + } + observer.updateCropOption() + } + + fun flipHorizontal() { + cropOptions = cropOptions?.copy(flipHorizontally = !cropOptions?.flipHorizontally!!) + observer.updateCropOption() + } + + fun flipVertical() { + cropOptions = cropOptions?.copy(flipVertically = !cropOptions?.flipVertically!!) + observer.updateCropOption() + } + + @SuppressLint("Range") + fun getLastCroppedImage(context: Context, uri: Uri): GalleryModel? { + try { + val columnsImages = arrayOf( + MediaStore.Images.Media.DATA, + MediaStore.Images.Media.DATE_MODIFIED, + MediaStore.Images.Media.DATE_ADDED, + "bucket_id", + "bucket_display_name", + MediaStore.Images.Media.DISPLAY_NAME, + MediaStore.Images.Media._ID + ) + val orderByimage = MediaStore.Images.Media.DATE_MODIFIED + val imagecursor = context.contentResolver.query( + uri, + columnsImages, null, null, "$orderByimage DESC" + ) + if (imagecursor != null && imagecursor.count > 0) { + imagecursor.moveToFirst() + val item = GalleryModel() + item.index_when_selected = 1 + item.isSelected = true + // get path + val dataColumnIndex = imagecursor + .getColumnIndex(MediaStore.Images.Media.DATA) + item.sdcardPath = imagecursor.getString(dataColumnIndex) + // get date modified + var dateColumnIndex = imagecursor + .getColumnIndex(MediaStore.Images.Media.DATE_MODIFIED) + var Image_date = imagecursor.getString(dateColumnIndex) + if (Image_date != null) { + item.item_date_modified = Integer.parseInt(Image_date) + } else { + dateColumnIndex = imagecursor + .getColumnIndex(MediaStore.Images.Media.DATE_ADDED) + Image_date = imagecursor.getString(dateColumnIndex) + if (Image_date != null) { + item.item_date_modified = Integer.parseInt(Image_date) + } else { + item.item_date_modified = SystemClock.elapsedRealtime().toInt() + } + } + //get Name + val nameColumnIndex = imagecursor + .getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME) + val name = imagecursor.getString(nameColumnIndex) + if (name != null) { + item.name = name + } else { + item.name = "unknown" + } + // get uri + // content://media/external/images/media/19490 + val imageuri = ContentUris + .withAppendedId( + MediaStore.Images.Media.EXTERNAL_CONTENT_URI, + imagecursor.getInt( + imagecursor + .getColumnIndex(MediaStore.Images.Media._ID) + ).toLong() + ) + item.itemUrI = imageuri.toString() + item.type = GalleryConstants.GalleryTypeImages + item.url = "file://" + item.sdcardPath + item.isVideo = false + //get albumName + val albumNameColumnIndex = imagecursor + .getColumnIndex("bucket_display_name") + item.albumName = imagecursor.getString(albumNameColumnIndex) + //add its album + imagecursor.close() + return item + } + } catch (e: Exception) { + e.printStackTrace() + } + return null + } + + interface Observer { + fun onBackClicked() + fun finishWithSuccess() + fun updateCropOption() + } +} \ No newline at end of file diff --git a/gallerylib/src/main/java/hashim/gallerylib/view/galleryActivity/BottomSheetGalleryFragment.kt b/gallerylib/src/main/java/hashim/gallerylib/view/galleryActivity/BottomSheetGalleryFragment.kt index 392c847..93c6196 100644 --- a/gallerylib/src/main/java/hashim/gallerylib/view/galleryActivity/BottomSheetGalleryFragment.kt +++ b/gallerylib/src/main/java/hashim/gallerylib/view/galleryActivity/BottomSheetGalleryFragment.kt @@ -48,6 +48,7 @@ import hashim.gallerylib.observer.OnResultCallback import hashim.gallerylib.util.DataProvider import hashim.gallerylib.util.GalleryConstants import hashim.gallerylib.util.ScreenSizeUtils +import hashim.gallerylib.view.selected.SelectedActivity import hashim.gallerylib.view.sub.BottomSheetAlbumsFragment import java.util.Collections @@ -103,6 +104,8 @@ class BottomSheetGalleryFragment : BottomSheetDialogFragment(), GalleryViewModel requireArguments().getInt(GalleryConstants.maxSelectionCount, 50) binding.viewModel?.columnsNumber?.value = requireArguments().getInt(GalleryConstants.gridColumnsCount, 3) + binding.viewModel?.isOpenEdit = + requireArguments().getBoolean(GalleryConstants.isOpenEdit, false) binding.viewModel?.showType = requireArguments().getString( GalleryConstants.showType, GalleryConstants.GalleryTypeImages @@ -127,30 +130,39 @@ class BottomSheetGalleryFragment : BottomSheetDialogFragment(), GalleryViewModel override fun openFinish() { binding.viewModel?.selectedPhotos = binding.viewModel?.recyclerGalleryAdapter?.getSelected() ?: ArrayList() - getIntentForSelectedItems(binding.viewModel?.selectedPhotos) - dismissAllowingStateLoss() - } - - override fun onBackClicked() { - binding.viewModel?.selectedPhotos = - binding.viewModel?.recyclerGalleryAdapter?.getSelected() ?: ArrayList() -// onResultCallback.onResult(binding.viewModel?.selectedPhotos!!) - dismissAllowingStateLoss() - } - - private fun getIntentForSelectedItems( - selected: ArrayList? - ) { // sort list as selected index - if (selected != null) { + if (binding.viewModel?.selectedPhotos != null) { Collections.sort( - selected, + binding.viewModel?.selectedPhotos!!, ComparableGalleryModel.instance.compareIndex_when_selected ) } - val intent = Intent() - intent.putExtra(GalleryConstants.selected, selected) - onResultCallback.onResult(binding.viewModel?.selectedPhotos!!) + if (binding.viewModel?.isOpenEdit == true) { + Intent(activity, SelectedActivity::class.java).also { + it.putExtra(GalleryConstants.selected, binding.viewModel?.selectedPhotos) + val locale = requireArguments().getString(GalleryConstants.Language) ?: GalleryConstants.ENGLISH + it.putExtra(GalleryConstants.Language, locale) + cropResultLauncher.launch(it) + } + + } else { + onResultCallback.onResult(binding.viewModel?.selectedPhotos!!) + dismissAllowingStateLoss() + } + } + + private var cropResultLauncher = + registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.resultCode == Activity.RESULT_OK) { + binding.viewModel?.selectedPhotos = + result.data?.extras?.get(GalleryConstants.selected) as ArrayList + onResultCallback.onResult(binding.viewModel?.selectedPhotos!!) + dismissAllowingStateLoss() + } + } + + override fun onBackClicked() { + dismissAllowingStateLoss() } override fun openAlbums() { diff --git a/gallerylib/src/main/java/hashim/gallerylib/view/galleryActivity/GalleryActivity.kt b/gallerylib/src/main/java/hashim/gallerylib/view/galleryActivity/GalleryActivity.kt index 2b26092..f9662b8 100644 --- a/gallerylib/src/main/java/hashim/gallerylib/view/galleryActivity/GalleryActivity.kt +++ b/gallerylib/src/main/java/hashim/gallerylib/view/galleryActivity/GalleryActivity.kt @@ -37,6 +37,7 @@ import hashim.gallerylib.util.DataProvider import hashim.gallerylib.util.GalleryConstants import hashim.gallerylib.util.ScreenSizeUtils import hashim.gallerylib.view.GalleryBaseActivity +import hashim.gallerylib.view.selected.SelectedActivity import hashim.gallerylib.view.sub.BottomSheetAlbumsFragment import java.util.* @@ -65,6 +66,8 @@ class GalleryActivity : GalleryBaseActivity( intent.getIntExtra(GalleryConstants.maxSelectionCount, 50) binding.viewModel?.columnsNumber?.value = intent.getIntExtra(GalleryConstants.gridColumnsCount, 3) + binding.viewModel?.isOpenEdit = + intent.getBooleanExtra(GalleryConstants.isOpenEdit, false) binding.viewModel?.showType = intent.getStringExtra(GalleryConstants.showType) ?: GalleryConstants.GalleryTypeImages @@ -77,11 +80,58 @@ class GalleryActivity : GalleryBaseActivity( } + override fun onBackClicked() { + finish_activity() + } + + @Suppress("DEPRECATION") + @Deprecated("") + override fun onBackPressed() { + finish_activity() + super.onBackPressed() + } + override fun openFinish() { binding.viewModel?.selectedPhotos = binding.viewModel?.recyclerGalleryAdapter?.getSelected() ?: ArrayList() - getIntentForSelectedItems(binding.viewModel?.selectedPhotos) - finish_activity() + // sort list as selected index + if (binding.viewModel?.selectedPhotos != null) { + Collections.sort( + binding.viewModel?.selectedPhotos!!, + ComparableGalleryModel.instance.compareIndex_when_selected + ) + } + if (binding.viewModel?.isOpenEdit == true) { + Intent(this@GalleryActivity, SelectedActivity::class.java).also { + it.putExtra(GalleryConstants.selected, binding.viewModel?.selectedPhotos) + var locale = "en" + if (intent.hasExtra(GalleryConstants.Language)) + locale = + intent.getStringExtra(GalleryConstants.Language) ?: GalleryConstants.ENGLISH + it.putExtra(GalleryConstants.Language, locale) + cropResultLauncher.launch(it) + } + + } else { + getIntentForSelectedItems() + finish_activity() + } + } + + private var cropResultLauncher = + registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.resultCode == Activity.RESULT_OK) { + binding.viewModel?.selectedPhotos = + result.data?.extras?.get(GalleryConstants.selected) as ArrayList + getIntentForSelectedItems() + finish_activity() + } + } + + private fun getIntentForSelectedItems() { + val intent = Intent() + intent.putExtra(GalleryConstants.selected, binding.viewModel?.selectedPhotos) + setResult(RESULT_OK, intent) } override fun openAlbums() { @@ -108,13 +158,6 @@ class GalleryActivity : GalleryBaseActivity( bottomSheetFragment.show(supportFragmentManager, bottomSheetFragment.tag) } - override fun onBackClicked() { - binding.viewModel?.selectedPhotos = - binding.viewModel?.recyclerGalleryAdapter?.getSelected() ?: ArrayList() - finish_activity() - } - - private fun fetchData() { if (checkPermissions()) Handler(Looper.getMainLooper()).post { @@ -369,26 +412,6 @@ class GalleryActivity : GalleryBaseActivity( } } - private fun getIntentForSelectedItems( - selected: ArrayList? - ) { - // sort list as selected index - if (selected != null) { - Collections.sort( - selected, - ComparableGalleryModel.instance.compareIndex_when_selected - ) - } - val intent = Intent() - intent.putExtra(GalleryConstants.selected, selected) - setResult(RESULT_OK, intent) - } - - override fun onBackPressed() { - finish_activity() - super.onBackPressed() - } - private var viewer: ImageViewer? = null override fun openImageViewer( position: Int, diff --git a/gallerylib/src/main/java/hashim/gallerylib/view/galleryActivity/GalleryViewModel.kt b/gallerylib/src/main/java/hashim/gallerylib/view/galleryActivity/GalleryViewModel.kt index 167da92..eee7f1e 100644 --- a/gallerylib/src/main/java/hashim/gallerylib/view/galleryActivity/GalleryViewModel.kt +++ b/gallerylib/src/main/java/hashim/gallerylib/view/galleryActivity/GalleryViewModel.kt @@ -24,6 +24,7 @@ class GalleryViewModel : ViewModel() { var albumModels: ArrayList = ArrayList() var showType = "" var maxSelectionCount = 10 + var isOpenEdit = false var selectedAlbumName = MutableLiveData("") var btnDoneVisible = MutableLiveData(false) var fromCameraContainer = MutableLiveData(false) diff --git a/gallerylib/src/main/java/hashim/gallerylib/view/galleryActivity/showMethod.kt b/gallerylib/src/main/java/hashim/gallerylib/view/galleryActivity/showMethod.kt index b55f780..c3efb1a 100644 --- a/gallerylib/src/main/java/hashim/gallerylib/view/galleryActivity/showMethod.kt +++ b/gallerylib/src/main/java/hashim/gallerylib/view/galleryActivity/showMethod.kt @@ -16,6 +16,7 @@ class GalleryLib(var myActivity: AppCompatActivity) { lateinit var myOnResultCallback: OnResultCallback fun showGallery( isDialog: Boolean, + isOpenEdit: Boolean, selectionType: String, locale: String, maxSelectionCount: Int, @@ -29,6 +30,7 @@ class GalleryLib(var myActivity: AppCompatActivity) { val bottomSheetFragment = BottomSheetGalleryFragment() val bundle = Bundle() bundle.putSerializable(GalleryConstants.selected, selected) + bundle.putSerializable(GalleryConstants.isOpenEdit, isOpenEdit) bundle.putSerializable(GalleryConstants.maxSelectionCount, maxSelectionCount) bundle.putSerializable(GalleryConstants.gridColumnsCount, gridColumnsCount) bundle.putSerializable(GalleryConstants.showType, selectionType) @@ -49,6 +51,7 @@ class GalleryLib(var myActivity: AppCompatActivity) { if (galleryResultLauncher == null) return Intent(myActivity, GalleryActivity::class.java).also { + it.putExtra(GalleryConstants.isOpenEdit, isOpenEdit) it.putExtra(GalleryConstants.maxSelectionCount, maxSelectionCount) it.putExtra(GalleryConstants.showType, selectionType) it.putExtra(GalleryConstants.selected, selected) diff --git a/gallerylib/src/main/java/hashim/gallerylib/view/selected/RecyclerSelectedPagerAdapter.kt b/gallerylib/src/main/java/hashim/gallerylib/view/selected/RecyclerSelectedPagerAdapter.kt new file mode 100644 index 0000000..f51dc8a --- /dev/null +++ b/gallerylib/src/main/java/hashim/gallerylib/view/selected/RecyclerSelectedPagerAdapter.kt @@ -0,0 +1,135 @@ +package hashim.gallerylib.view.selected + +import android.graphics.Color +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import androidx.media3.common.AudioAttributes +import androidx.media3.common.C +import androidx.media3.common.MediaItem +import androidx.media3.common.PlaybackException +import androidx.media3.common.Player +import androidx.media3.exoplayer.ExoPlayer +import androidx.media3.ui.AspectRatioFrameLayout +import androidx.recyclerview.widget.RecyclerView +import hashim.gallerylib.R +import hashim.gallerylib.databinding.ItemPagerSelectedBinding +import hashim.gallerylib.model.GalleryModel +import hashim.gallerylib.util.GalleryConstants + +class RecyclerSelectedPagerAdapter( + val models: ArrayList, +) : RecyclerView.Adapter() { + override fun onCreateViewHolder( + parent: ViewGroup, + viewType: Int + ): ViewHolder { + val inflater = LayoutInflater.from(parent.context) + val binding = DataBindingUtil.inflate( + inflater, + R.layout.item_pager_selected, + parent, + false + ) as ItemPagerSelectedBinding + return ViewHolder( + binding + ) + } + + override fun getItemCount() = models.size + + + override fun onBindViewHolder( + holder: ViewHolder, + position: Int + ) { + val item = models[holder.layoutPosition] + + holder.binding.model = item + if (item.type.compareTo(GalleryConstants.GalleryTypeVideos) == 0) { + if (item.isReleasePlayer) { + models[holder.layoutPosition].player?.release() + } else { + initVideoPlayer(item, holder) + } + + } + holder.itemView.setOnClickListener { + } + + } + + @androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class) + private fun initVideoPlayer(model: GalleryModel, holder: ViewHolder) { + model.player = + ExoPlayer.Builder(holder.binding.videoView.context).build().also { exoPlayer -> + holder.binding.videoView.player = exoPlayer + exoPlayer.setMediaItem( + MediaItem.fromUri(model.itemUrI) + ) + exoPlayer.playWhenReady = false + exoPlayer.addListener(object : Player.Listener { + override fun onIsLoadingChanged(isLoading: Boolean) { + super.onIsLoadingChanged(isLoading) + } + + override fun onPlayerError(error: PlaybackException) { + super.onPlayerError(error) + } + + override fun onPlaybackStateChanged(playbackState: Int) { + when (playbackState) { + Player.STATE_IDLE -> {} + Player.STATE_BUFFERING -> {} + Player.STATE_READY -> { + } + + Player.STATE_ENDED -> { + } + } + } + }) + val audioAttributes = AudioAttributes.Builder().setUsage(C.USAGE_MEDIA) + .setContentType(C.AUDIO_CONTENT_TYPE_MOVIE).build() + exoPlayer.setAudioAttributes(audioAttributes, false) +// exoPlayer.setAudioAttributes(AudioAttributes.DEFAULT, true) + //This will increase video's height or width to fit with maintaining aspect ratios of video. + holder.binding.videoView.resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT + //player seekbar controller + holder.binding.videoView.useController = true + exoPlayer.volume = 1.0f + holder.binding.videoView.setShutterBackgroundColor(Color.BLACK) + exoPlayer.prepare() + } + } + +// override fun onViewRecycled(holder: ViewHolder) { +// if (models[holder.layoutPosition].type.compareTo(GalleryConstants.GalleryTypeVideos) == 0 && models[holder.layoutPosition].player != null) { +// models[holder.layoutPosition].player!!.release() +// models[holder.layoutPosition].player = null +// } +// super.onViewRecycled(holder) +// } + +// override fun onViewDetachedFromWindow(holder: ViewHolder) { +// if (models[holder.layoutPosition].type.compareTo(GalleryConstants.GalleryTypeVideos) == 0 && models[holder.layoutPosition].player != null) { +// models[holder.layoutPosition].player!!.stop() +// models[holder.layoutPosition].player!!.release() +// } +// super.onViewDetachedFromWindow(holder) +// } +// +// override fun onViewAttachedToWindow(holder: ViewHolder) { +// if (models[holder.layoutPosition].type.compareTo(GalleryConstants.GalleryTypeVideos) == 0) { +// initVideoPlayer(models[holder.layoutPosition], holder) +// } +// super.onViewAttachedToWindow(holder) +// } + + class ViewHolder(var binding: ItemPagerSelectedBinding) : + RecyclerView.ViewHolder(binding.root) { + + } + + +} \ No newline at end of file diff --git a/gallerylib/src/main/java/hashim/gallerylib/view/selected/SelectedActivity.kt b/gallerylib/src/main/java/hashim/gallerylib/view/selected/SelectedActivity.kt new file mode 100644 index 0000000..a6805dd --- /dev/null +++ b/gallerylib/src/main/java/hashim/gallerylib/view/selected/SelectedActivity.kt @@ -0,0 +1,174 @@ +package hashim.gallerylib.view.selected + +import android.app.Activity +import android.content.Intent +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.view.View +import androidx.activity.result.contract.ActivityResultContracts +import androidx.lifecycle.ViewModelProvider +import androidx.recyclerview.widget.RecyclerView +import androidx.viewpager2.widget.MarginPageTransformer +import androidx.viewpager2.widget.ViewPager2 +import hashim.gallerylib.R +import hashim.gallerylib.databinding.ActivitySelectedBinding +import hashim.gallerylib.model.GalleryModel +import hashim.gallerylib.util.GalleryConstants +import hashim.gallerylib.util.dpToPx +import hashim.gallerylib.view.GalleryBaseActivity +import hashim.gallerylib.view.crop.CropActivity + +class SelectedActivity : + GalleryBaseActivity( + R.string.gallery, false, true, true, false, + false, true, true + ), SelectedViewModel.Observer { + lateinit var binding: ActivitySelectedBinding + override fun doOnCreate(arg0: Bundle?) { + binding = putContentView(R.layout.activity_selected) as ActivitySelectedBinding + binding.viewModel = ViewModelProvider(this)[SelectedViewModel::class.java] + binding.viewModel?.observer = this + binding.lifecycleOwner = this + initializeViews() + setListener() + } + + override fun initializeViews() { + binding.viewModel?.selectedPhotos = + intent.extras!!.get(GalleryConstants.selected) as ArrayList + initViewPager() + } + + val pagerAutoScrollHandler = Handler(Looper.getMainLooper()) + fun initViewPager() { + binding.viewPagerActivityLanguage.visibility = View.VISIBLE + binding.viewPagerActivityLanguage.apply { + clipToPadding = false // allow full width shown with padding + clipChildren = false // allow left/right item is not clipped + offscreenPageLimit = 1 // make sure left/right item is rendered + val recyclerView = getChildAt(0) as RecyclerView + recyclerView.apply { + //set items padding, when more padding, item close to other + // setting padding on inner RecyclerView puts overscroll effect in the right place + clipToPadding = false + //adapter + binding.viewModel?.selectedPagerAdapter = + RecyclerSelectedPagerAdapter( + binding.viewModel?.selectedPhotos!! + ) + adapter = binding.viewModel?.selectedPagerAdapter + } + val offsetPx = + resources.getDimension(R.dimen.padding_0).toInt() + .dpToPx(resources.displayMetrics) + setPadding(0, 0, offsetPx, 0) + val pageMarginPx = + resources.getDimension(R.dimen.padding_1).toInt() + .dpToPx(resources.displayMetrics) + val marginTransformer = MarginPageTransformer(pageMarginPx) + setPageTransformer(marginTransformer) + } + + binding.viewPagerActivityLanguage.registerOnPageChangeCallback(object : + ViewPager2.OnPageChangeCallback() { + var previousPosition = -1 + override fun onPageScrolled( + position: Int, + positionOffset: Float, + positionOffsetPixels: Int + ) { + super.onPageScrolled(position, positionOffset, positionOffsetPixels) + + } + + override fun onPageScrollStateChanged(state: Int) { + super.onPageScrollStateChanged(state) + if (state == ViewPager2.SCROLL_STATE_DRAGGING) pagerAutoScrollHandler.removeMessages( + 0 + ) + } + + override fun onPageSelected(position: Int) { + super.onPageSelected(position) + if (previousPosition != -1 && binding.viewModel?.selectedPhotos!![previousPosition].type.compareTo( + GalleryConstants.GalleryTypeVideos + ) == 0 + ) { + //release player for + binding.viewModel?.selectedPhotos!![previousPosition].isReleasePlayer = true + binding.viewModel?.selectedPagerAdapter?.notifyItemChanged(previousPosition) + } + if (binding.viewModel?.selectedPhotos!![position].type.compareTo(GalleryConstants.GalleryTypeVideos) == 0) { + binding.viewModel?.selectedPhotos!![position].isReleasePlayer = false + binding.viewModel?.selectedPagerAdapter?.notifyItemChanged(position) + } + //set current position to previous + previousPosition = position + //hide show crop button based on view type + binding.imgviewCrop.visibility = + if (binding.viewModel?.selectedPhotos!![binding.viewPagerActivityLanguage.currentItem].type.compareTo( + GalleryConstants.GalleryTypeImages + ) == 0 + ) { + View.VISIBLE + } else View.GONE + } + }) + } + + override fun setListener() { + } + + override fun cropImage() { + if (!binding.viewModel?.selectedPhotos.isNullOrEmpty() + && binding.viewModel?.selectedPhotos!![binding.viewPagerActivityLanguage.currentItem].type.compareTo( + GalleryConstants.GalleryTypeImages + ) == 0 + ) { + Intent(this, CropActivity::class.java).also { + val galleryModels = ArrayList() + galleryModels.add(binding.viewModel?.selectedPhotos!![binding.viewPagerActivityLanguage.currentItem]) + it.putExtra("GalleryModels", galleryModels) + it.putExtra("position", binding.viewPagerActivityLanguage.currentItem) + var locale = "en" + if (intent.hasExtra(GalleryConstants.Language)) + locale = + intent.getStringExtra(GalleryConstants.Language) ?: GalleryConstants.ENGLISH + it.putExtra(GalleryConstants.Language, locale) + cropResultLauncher.launch(it) + } + } + } + + private var cropResultLauncher = + registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.resultCode == Activity.RESULT_OK) { + val position = result.data?.extras?.getInt("position", -1) ?: -1 + if (position != -1) { + val galleryModels = + result.data?.extras?.get("GalleryModels") as ArrayList + if (!galleryModels.isNullOrEmpty()) { + binding.viewModel?.selectedPhotos!![position] = galleryModels[0] + binding.viewModel?.selectedPagerAdapter?.notifyItemChanged(position) + } + } + } + + } + + override fun onBackClicked() { + finish_activity() + } + + override fun finishWithSuccess() { + for (i in binding.viewModel?.selectedPhotos!!.indices) { + binding.viewModel?.selectedPhotos!![i].player = null + } + val intent = Intent() + intent.putExtra(GalleryConstants.selected, binding.viewModel?.selectedPhotos) + setResult(RESULT_OK, intent) + finish_activity() + } + +} \ No newline at end of file diff --git a/gallerylib/src/main/java/hashim/gallerylib/view/selected/SelectedPageFragment.kt b/gallerylib/src/main/java/hashim/gallerylib/view/selected/SelectedPageFragment.kt new file mode 100644 index 0000000..3ef3944 --- /dev/null +++ b/gallerylib/src/main/java/hashim/gallerylib/view/selected/SelectedPageFragment.kt @@ -0,0 +1,109 @@ +package hashim.gallerylib.view.selected + +import android.content.Intent +import android.graphics.Color +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import androidx.fragment.app.Fragment +import androidx.media3.common.AudioAttributes +import androidx.media3.common.C +import androidx.media3.common.MediaItem +import androidx.media3.common.PlaybackException +import androidx.media3.common.Player +import androidx.media3.exoplayer.ExoPlayer +import androidx.media3.ui.AspectRatioFrameLayout +import hashim.gallerylib.R +import hashim.gallerylib.databinding.ItemPagerSelectedBinding +import hashim.gallerylib.model.GalleryModel +import hashim.gallerylib.util.GalleryConstants +import hashim.gallerylib.view.crop.CropActivity + +class SelectedPageFragment : Fragment() { + + private lateinit var galleryModel: GalleryModel + + lateinit var binding: ItemPagerSelectedBinding + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, savedInstanceState: Bundle? + ): View { + binding = + DataBindingUtil.inflate(layoutInflater, R.layout.item_pager_selected, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + galleryModel = requireArguments().getSerializable("GalleryModel") as GalleryModel + binding.model = galleryModel + } + + override fun onResume() { + super.onResume() + if (galleryModel.type.compareTo(GalleryConstants.GalleryTypeVideos) == 0) + initVideoPlayer(galleryModel) + } + + override fun onPause() { + super.onPause() + + } + + @androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class) + private fun initVideoPlayer(model: GalleryModel) { + model.player = ExoPlayer.Builder(binding.videoView.context).build().also { exoPlayer -> + binding.videoView.player = exoPlayer + exoPlayer.setMediaItem( + MediaItem.fromUri(model.itemUrI) + ) + exoPlayer.playWhenReady = false + exoPlayer.addListener(object : Player.Listener { + override fun onIsLoadingChanged(isLoading: Boolean) { + super.onIsLoadingChanged(isLoading) + } + + override fun onPlayerError(error: PlaybackException) { + super.onPlayerError(error) + } + + override fun onPlaybackStateChanged(playbackState: Int) { + when (playbackState) { + Player.STATE_IDLE -> {} + Player.STATE_BUFFERING -> {} + Player.STATE_READY -> { + } + + Player.STATE_ENDED -> { + } + } + } + }) + val audioAttributes = AudioAttributes.Builder().setUsage(C.USAGE_MEDIA) + .setContentType(C.AUDIO_CONTENT_TYPE_MOVIE).build() + exoPlayer.setAudioAttributes(audioAttributes, false) +// exoPlayer.setAudioAttributes(AudioAttributes.DEFAULT, true) + //This will increase video's height or width to fit with maintaining aspect ratios of video. + binding.videoView.resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT + //player seekbar controller + binding.videoView.useController = true + exoPlayer.volume = 1.0f + binding.videoView.setShutterBackgroundColor(Color.BLACK) + exoPlayer.prepare() + } + } + + override fun onDestroy() { + super.onDestroy() + + } + + override fun onDetach() { + super.onDetach() +// if (galleryModel.player != null) +// galleryModel.player?.release() +// galleryModel.player = null + } +} \ No newline at end of file diff --git a/gallerylib/src/main/java/hashim/gallerylib/view/selected/SelectedViewModel.kt b/gallerylib/src/main/java/hashim/gallerylib/view/selected/SelectedViewModel.kt new file mode 100644 index 0000000..d983d1a --- /dev/null +++ b/gallerylib/src/main/java/hashim/gallerylib/view/selected/SelectedViewModel.kt @@ -0,0 +1,16 @@ +package hashim.gallerylib.view.selected + +import androidx.lifecycle.ViewModel +import hashim.gallerylib.model.GalleryModel + +class SelectedViewModel : ViewModel() { + lateinit var observer: Observer + lateinit var selectedPagerAdapter: RecyclerSelectedPagerAdapter + var selectedPhotos: ArrayList = ArrayList() + + interface Observer { + fun cropImage() + fun onBackClicked() + fun finishWithSuccess() + } +} \ No newline at end of file diff --git a/gallerylib/src/main/res/drawable-anydpi/crop_icon.xml b/gallerylib/src/main/res/drawable-anydpi/crop_icon.xml new file mode 100644 index 0000000..141a245 --- /dev/null +++ b/gallerylib/src/main/res/drawable-anydpi/crop_icon.xml @@ -0,0 +1,11 @@ + + + diff --git a/gallerylib/src/main/res/drawable-anydpi/rotate_icon.xml b/gallerylib/src/main/res/drawable-anydpi/rotate_icon.xml new file mode 100644 index 0000000..72aee6c --- /dev/null +++ b/gallerylib/src/main/res/drawable-anydpi/rotate_icon.xml @@ -0,0 +1,12 @@ + + + diff --git a/gallerylib/src/main/res/drawable-hdpi/crop_icon.png b/gallerylib/src/main/res/drawable-hdpi/crop_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..aae97a2ec2f33f658c84b9f518de584cb5130d0c GIT binary patch literal 369 zcmV-%0gnEOP)oo+z z_$ACY#vIAHeZu-H^5CAmVDd5;cgeC2@y?AA4)x7_JINJ@gzlbj?^Y1#9EKYyoM;<1 z;$Im)mvU~Ou>V)s2jgq*J&IHpH4gK{x^yS&gV8`SG*Ao;6hi~W&_FSGApT!A7OXYU zGYNZ@vObtp9ZJUR0wKsE1j1v(XK4Er!h7F^^xpwpIbav#)OwWutswnJ%i<|CED%8t z=m>U?MXP;;_3!@A7~?ltCuMzAcd70}sn9?%G*AqB??b2u5(1sd`mFf{V4irx5plKX P00000NkvXXu0mjf^kk); literal 0 HcmV?d00001 diff --git a/gallerylib/src/main/res/drawable-hdpi/flip_horizontal_white_icon.png b/gallerylib/src/main/res/drawable-hdpi/flip_horizontal_white_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ee3e09eebb836ef3c31128ae4117cdaea8495d03 GIT binary patch literal 412 zcmV;N0b~A&P)9B+>#wK=MxMQs+JvnB^*P_Z8cO&HC0<4 zItup4lMU9qqH?`9P7%)8BxkX?ij!4xX*I%{^3cp`#8&tiYbwxMewmqsBeT!V%TA$C8 zY^dgiTp(y8KX=I~%#dQ_9BFxfY^dfSFr>D0gXhC<=EwLyhMtj0%d&Z?v)c9=|Mfq{ z?2e9H4%Y|R;VRbyN_3JadvUN znI*f~9~bn%2a}m|?;Xg@?Ch?rBou%e*(7^pKOyoere^bH7L$(1BY8@RVn#M!W-;lE zd@RY#=F2Q5osu_Cu|+6mYV&0llXl3hr{E$K)3Nz-5fcx|tEXrj@(yjD+{EN9q+3h! zwrrkU#R7e}-D8Ve^Gp2->@34el|rO?KdRoKRbR8k0v}#VA%e)UMk)i4_z%fxDcolVfsD4oEi`JA<2u zP+NT(lSf{~C{{T%mhDJ@dsM7O+H=2+_v^PjzTctu?+9+&9|ipGwuf7+7x+FH)oxf{ zX=3pKe%_7L9#~%~g4==Dk;#OpFWXL9Ml3o;{PkmO{e=o{A>Vl>6QZ$l7C5SQg=LW* zl3((BHa=IuJ)^EX#p95-xYr<5=|vG$dzD57KQ^R!g|-y(Ic7v2F#kbn5ruuQ()rUx g`cHa_NqioC0_}&K$}{!a9RL6T07*qoM6N<$f{gz49smFU literal 0 HcmV?d00001 diff --git a/gallerylib/src/main/res/drawable-hdpi/rotate_icon.png b/gallerylib/src/main/res/drawable-hdpi/rotate_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..6a9a7e06d0271096ed25a71815bbdbd465cd979c GIT binary patch literal 584 zcmV-O0=NB%P)%jvknG2#jZY|DWy_r1!g`vytr#L8jS_j$pnb6>&p-i z<#M?SlgFAv+k2r<7>*fMMqc)WSaf+^)HLJ!{;bt-*ys8pUNb+_gl+wb<|*4p4Rxyw z2DU~mYHBVub^)_8o|qxd5Y6Utxp~bK&uPu~3a6aajQ<^M zYd#T~^U?F?3}MP%vYxVfy}r$W_J-yYfsq?$2y-53zE`j@e4}@*`9vVlbOIPrTl2jF zoeQT&ZOx}4)xnsCOb$kZ%AA`j@#>h=K54+S6{B;i`P6V^ybz7pv)897tecQp(IA&A z3Bz#JmK(y4-EMSCu~=Nv%>XmY_IKYvc+;ASt96IZz^*NR#{dH4Zp{EftCbl+5ac2L zsm6E}xIXy4qxpE6vZ;*13fP67WQYrR;5CyLROKw}5w9(Y2|Fu- zjRg}6k0IjmFR&B-087I^;1BQ^Os^zj5|8kaO4lUiX1eG0?Y{0r=9l!QbIz%6PMtb+ z>So!J{&%5?y||56XyFHD@fI&|3u9Q(A;uLn`UP2yOA(-`KHxHjaxnS=!g0Lo0c1X~ zqX|qoAT)3dzjF(Ot+|i=7{;2I!Ob{`o0whzvQY-+aV|*6(s-z&0{+W!GG=EWKp``! zo`g*F6r>&Jdfz}emfNN~W%fK*Gv$D=D%MDvnKCe2aihzxFwn&W<~`PCH8;JP1ZccA zmnE)MF3_$5UHM|&rz9m5Qovsc*>ndDlC|PH=o8ipA z*fMNSdtEofsl;%sLZIErZScIC;ba2zpemqby)D?)&0sV)YBaMtg=M)qI$gmUr*IZ4 zi#l9LfTjm|+Tuj{CAqkFmKi^uh0F~I=v)%_O&EKNIv&XlXmsa%TV(nJsUn(f8bc1X00000NkvXXu0mjfB1;Ew literal 0 HcmV?d00001 diff --git a/gallerylib/src/main/res/drawable-mdpi/crop_icon.png b/gallerylib/src/main/res/drawable-mdpi/crop_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..b1544896a5ec9ee2c2f05793a7eb32feefee7ae1 GIT binary patch literal 168 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gj`JOJ0Ar*0Nr#SL8DDbfSY`eeU zua;Z=YTJxcUO5xoY)dBXy^zvgq_9+9VbRQ);Wp*UEaFQ7)SvIkU_2+SS*>=lVO5G_1FE+EEhi07~m*0u`XX?+7TAdmGY$TqSMKG;n5 zy~!roO_HdnXF2EkV9NEkf*}P1(B*q9%;|wK*IAOKnW^p literal 0 HcmV?d00001 diff --git a/gallerylib/src/main/res/drawable-mdpi/flip_vertical_white_icon.png b/gallerylib/src/main/res/drawable-mdpi/flip_vertical_white_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..7c916f985c2b1319fe0c4b3e5d58a02a843cb6ef GIT binary patch literal 339 zcmV-Z0j&OsP)%0i)a(nPFmOj+8a?fh+24nE+Ex4qI0y5)@=*A)8BhI=I}G3X+{q|9Oi%j z8^O`B(oP4o9GGu475JE3X5CJ@@wNoI=4IfeDy_wFzB;sexn8u|^NQkp^XSiw6hU&1g~Mx+d41oz%XIMM&eK52TS11&YRuY z&3fK15y$aHYlD(y*&|7kQtN|(0)rPx({w_nJ2vMrNV{mI7aDhMF2+*lI72JHik2M0 zFkGk|9CeN}WPXAPeQ&<+k634O($8{!5CmiFR%%v?qQK;)Ez%sA0&A%OECe~o)v*?2 zu;;eu7-=i50UWs5*;dC|a2xVGpX!(m%;h{CYvDZcRX$eWoh{-+c76_e9dg$-wL!+U z^ECywAI%1SG~{T#6ZKS-Q54NZYz7SrfVs@;1({d!v11)AF@+JUWKM6)bKM-g&}tm0 dbI<>Ll_$avba&fR>#P6(002ovPDHLkV1joljSBz( literal 0 HcmV?d00001 diff --git a/gallerylib/src/main/res/drawable-mdpi/rotate_white_icon.png b/gallerylib/src/main/res/drawable-mdpi/rotate_white_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..fb2d1a2b318258d0815c577bc07627defbd21157 GIT binary patch literal 407 zcmV;I0cie-P)=Dg4UJVV-`y>AYN#e`F!%wQk#}6^GYWG8v$5;aPw3+3czsE3E_7DUOrj? zUWLb1Mxf5vEBziwqGl^i719zNl1I>M<52BLQEUqvn2o_0D;7mwpu zV_l}FX8ap|;X_;IbrDSACl2Ccyv9D>lrnvCx&!DAMy&-7nLq#l002ovPDHLkV1lev Bq_6-0 literal 0 HcmV?d00001 diff --git a/gallerylib/src/main/res/drawable-xhdpi/crop_icon.png b/gallerylib/src/main/res/drawable-xhdpi/crop_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..6ae6bcaf2717577e01322e5b2ccaca164d3b8cdd GIT binary patch literal 277 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpUtJDx6%Ar*0N`yIKM3z>iRuy_m?kc+p&@{FRNkpOZFG+n|to< z_s)JRv?}!O?10E=7k~SA3U0q3du9HjMLLVW-xpH$d*vVK2^80PCEupE;BN)v+vD6B z_HhosKQi6w7r#)qr{UXU)-Ce-IHl(6F92Fsm)BtZYyT7rtJOy&|K1n7cI{TI>$(@u w%>8QM|f~;)AS{2l7nr$qwmMYh)JJ7=-JA zq8`g4@!~y+H}NQ5#dDhsj=|OGr{a#Rk^#M7TJhW^azlFbSQ<%e??Jq1e^+EwCY7p8 z5F&CyW|89;LCyr=N?Q8o*n7~vgj+IEFM*gRvP*_^uv+5$dAKW;I(doVV?C0O1TQh- zxs*16m>04Mx4);_+c~dSAJdYx$S~RPF?8G{awQ;?$t7G9b!jt|f~(;L)M#Q^gRGHr z@}3Z{8o3jQk=@`3Zfi?42xtBRRTAa#adP0-((Bjb*9pW#WFKxf`;iC|ni#HJWbPh$ zO;|524ND;A46qD5!-NmMT~XsUwmi+L-?| zzHeq0WbWMTW^eZF9=R_(WbfJex;MLfX3y@(NKJ{z7`O|T281!jeEdd*gcIN~_z1oX z2xBnTgwNBMkZc8f1LxNSW3Bi+jS0y%!AVd^T^MWA=V?qxwhX=oh17+ymVKVagkw`Unva)UqUXZ%pujTd)6TK)g+k`QkD$nY(00zpX;mm_5Bv^__0VR|`?oF> zwE*4+1$$_-;Qd>dXm`q{?6MYv`)HH4`>ZMyHU*A?!V9=>%KLRnqJ2^{xp6FAzf)Hz zaugf{Uw~ty-oBF(y~}zH&Wtx4^LCw;{TG(N6NB4%{Q5%;)kmT;?IW-%I%&;<4P)JG z*j_)hu?Jw<;5Ns&@1lLC&p-Z*#h8rE9M?ZnBj}ds637d1+dh9XK7d=I1-`Q}whWvT z2)8-LeYBx1eF}fZVob(njxC>mV2S=hH^kO&M6WbAjf=L}#yA^ujDPvLXUuHbh8O>qSz|Ed8eFE(XdS@;AI2x2Xmz@^z1{B-~Bq9N!Koq15B|<=ffClAlnL&l z(iGYGJv*~k)^0Rv7L;zcd%(6z;rsr?^SpDmR|YL0uzmU}fl-zrQUT_fhQClKh{QZeur_&6QrScf~|!S!s?~8ON zoz9vh|HFjTr2SJ88?;)jE&8B)VBEq8OJ0`5hN+{!6v;~h@0Nt_s8gs5wAa)TnZXOT zIU!`jo>4c2T0LH=A)*5K$jOq#fM08{G8EIOkCN;Kmo*I%Q zd4=)ixnpWl!{FSoHi9GuY!5?YvL9+vA%S)f_=6f7lF%XBqR`k$2PzWXd}h!*?=m`L zW?%CAo|?q?I67ri)~Rs?{{UsMUZ_co1o<+9(qDSaHt=L{@lH4}qklPE* z6yNennPDcD*q})Amuz#27xSfl7XJUqHl{Ck;(S(Vx7(Y1PLmejjcC5{%!t}TkYwIi zfN9jzZ(43&BBHQu>=Xs;QClcsA9tyvKRD;z9+g=!Kd;j#2|tSslWg{ynwpxLnkaq& XB8#JQK9a7t00000NkvXXu0mjf%h3{* literal 0 HcmV?d00001 diff --git a/gallerylib/src/main/res/drawable-xhdpi/rotate_white_icon.png b/gallerylib/src/main/res/drawable-xhdpi/rotate_white_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ff8df4c3deb7918f9ff94e5d68026001c98e8079 GIT binary patch literal 778 zcmV+l1NHogP)@-1|g%OE_^HmcOtqr zA;yJZq7Y1Up$i`f;=zq23Wj%WIC=EWqBK(N+xPhnm2QP68SMW2oU>^EL5O>!|o+~4KHumF= z;@rhf%os+zS`1)1j^l6T`3pxdHAj5)2CyEFRL?!ENyJxY0OR9ZABsP53SVO&EDcP+ zWX#2axc+~_ivq^_st`X37l#<&CN_j;3dEa=&G@5s1M$u0iGPLf!v9OYnBDldP6Nk> z*g?K175HuZUA4_X{9seAVpf;LcWwaF@X)*5$DE49Z#ObJHgGIw%~!H)YDX)>rb%jR z))cTW5&vtM-DWfjvpb1_FSDkAg^BoQMUvF0gC7zDr?V!ZRkOFVF>4aIo)}n=H3>XU z4CEd-#w_07|0iZm!Wc53Rjs!3vQbM2a}q6gJNbwgc13LtSe|IP+^B67%VIlb@W6Aj zlSFo=D{6-UQ?MF~NAhque5a+vUYEhd54z-ONw)JnbqTp!Gk#eALpyK1Mz?)?3-Blgx?^V^27-rnLvGXxVI9&C2 z8f=~SxmtI2Mt^KUhM8DdHdyE!r~Ho3Dipjl?Dfgt`a&kIB6w&mUdS==D)#sLOD3p; z@lBtv?J^@)g?T0hzl%*plU?jw-%4VAUyFgZnK*1{p5rXOiH(7o_%NCeRpm-7Nn)Nz zVuUNHPiiv}2VIK?I^$9j>(jPEEwn9H)hfPi;E&^MgzKRqgjpJw#5#!s?N>})Bjg0^ z$yv+8@p(2z3&4TcaSr?UH9W!VSdxT<_zTWq{%Gs%(c}Nbf3M+>KmT|p2mk;807*qo IM6N<$f(5K<+yDRo literal 0 HcmV?d00001 diff --git a/gallerylib/src/main/res/drawable-xxhdpi/crop_icon.png b/gallerylib/src/main/res/drawable-xxhdpi/crop_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..4b375b013f659c6bef5fd3232065668cf5506ac6 GIT binary patch literal 490 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@Zgyv2VBF~G;uum9_jabC-{AlO*6RgA z77j~(?0%NlA*LzHy8Y;W2PfwTw?DF3r@2)vQmCr4UgFp%FmbIB&*9%Yd-lKjakHND zs0K$sPZI-P>P>9Gac6zsw@H;M-~LbA_ul{Ud3QUT<}J)w;-{52)_Zwro|oA$1;)*C z^VFBw*aGAF@wFdjZjbT0#kjTm>BJlM#_D`K;cD|NQaHUTTZ z7DN`DU~#mdKI;Vst0A@SE A*#H0l literal 0 HcmV?d00001 diff --git a/gallerylib/src/main/res/drawable-xxhdpi/flip_horizontal_white_icon.png b/gallerylib/src/main/res/drawable-xxhdpi/flip_horizontal_white_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..5ccc1f90e57b1ee404ccaad6fdcafc240251f30b GIT binary patch literal 978 zcmV;@11te?#zTs?0_V41v|4 z&7>#&z2yr3!Hwi7IZn2bS!uf>6--hbO&dMRk!%k+D|dO&n>Ny_agf|3&&dmNpPYpi z&Q27(s=&;d3!7%61I$^sl%sN0&dU7;%!{u00xhlg$TwJ#6u-z9a)%rtD^XzJ zuvJXc>j7DSf<}>Y2)QUH<)$2!YnHb>xJy>W7ab1R{#%ekZGt@u)oqSq2(c(8#g@if z4Y?YmDWO2#k;}09G$V?+CZSGqVAE+Gxfo(mO!4Ye3%ME;^O-z`6~i@TT9m_>f=!7f zgXJ|dq`8dt3pW{}W-?KQbhj*%6pVpL$H1}P2||BkdxELahip(?=F z!aeI9F)4)_l%XN6CG`T?OZuYxN`xAgdHyz^>>}sLGt^#$$D=6*W$4LN1@jbaDrlsX zOdpJ6kgkE%8TE0JJcX@z>HYGcsRqT|CTmgVZ5@{U9$3;#kxa4hyNa;-Nc+v3mKh{2 zk^Yg?|HhzVyB_x9I1fqP;@^wNl`{PmK}!wNO1C=7y(;M%*o$S_UlF)L(^b literal 0 HcmV?d00001 diff --git a/gallerylib/src/main/res/drawable-xxhdpi/flip_vertical_white_icon.png b/gallerylib/src/main/res/drawable-xxhdpi/flip_vertical_white_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..b6d24db0fe01bd26157f17ade7e5ca53fb8856d3 GIT binary patch literal 1272 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 literal 0 HcmV?d00001 diff --git a/gallerylib/src/main/res/drawable-xxxhdpi/rotate_white_icon.png b/gallerylib/src/main/res/drawable-xxxhdpi/rotate_white_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..375f6cfee9ca630c88abb8072546c42523f407ac GIT binary patch literal 1523 zcmVhT50G6A?9 z_<&9@0C13OqT1zm-~r%>5@kCISOEMPr2&A$WNqCJKLay>y(^T{x~$m+8KNtsJHH*} z?*JYvGgjjuvz<4V=A5UxLhApDjiiof%UCP${-yZj;2u-YwO!y1^#HFn{ibg z$V@OD4lq&-VoPFINdKapiu&_4iUDpdWS~TIq~bk`_mb|)FGbSG@9z?sF%R3kB8z!R zeREU$Pl9%a z+>9+Up^vL*-ugz7#~SA%Q%7tZNFL+i@;-2zO7}M%6vzK)hOSQQLw6EVJ4Fd1C z^=LN!F0O90L}y3Irf{OA)uy8epx1Ob-tF{)fP6CT1kQ-s5nxRs;ju zu3Mf?+luX~j>>VB3G`}*K6H7R;vkFvcL4YVI8I(IqLsuBhkJZqU)|i(RLMnM + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gallerylib/src/main/res/layout/activity_crop.xml b/gallerylib/src/main/res/layout/activity_crop.xml new file mode 100644 index 0000000..7507563 --- /dev/null +++ b/gallerylib/src/main/res/layout/activity_crop.xml @@ -0,0 +1,281 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gallerylib/src/main/res/layout/activity_selected.xml b/gallerylib/src/main/res/layout/activity_selected.xml new file mode 100644 index 0000000..7bb8716 --- /dev/null +++ b/gallerylib/src/main/res/layout/activity_selected.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gallerylib/src/main/res/layout/item_pager_gallery.xml b/gallerylib/src/main/res/layout/item_pager_gallery.xml index 8b39af9..0288c7f 100644 --- a/gallerylib/src/main/res/layout/item_pager_gallery.xml +++ b/gallerylib/src/main/res/layout/item_pager_gallery.xml @@ -31,7 +31,6 @@ android:adjustViewBounds="true" android:background="@color/black" android:contentDescription="@string/app_name" - android:scaleType="centerCrop" android:src="@drawable/round_5_bg_gray_light" app:imageUrlRect="@{model.url}" /> @@ -56,7 +55,7 @@ android:gravity="center" android:padding="@dimen/padding_4" android:src="@{model.selected?@drawable/done_white_icon:@drawable/transparent}" - android:visibility="@{showCounter?View.GONE:View.VISIBLE}" + android:visibility="gone" app:tint="@color/white" /> + android:visibility="gone" /> \ No newline at end of file diff --git a/gallerylib/src/main/res/layout/item_pager_selected.xml b/gallerylib/src/main/res/layout/item_pager_selected.xml new file mode 100644 index 0000000..22c3f58 --- /dev/null +++ b/gallerylib/src/main/res/layout/item_pager_selected.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gallerylib/src/main/res/values-ar/strings.xml b/gallerylib/src/main/res/values-ar/strings.xml index c4a1e94..42d28ad 100644 --- a/gallerylib/src/main/res/values-ar/strings.xml +++ b/gallerylib/src/main/res/values-ar/strings.xml @@ -18,4 +18,14 @@ الإعدادت لايمكن اختيار اكثر من %s عنصر من فضلك انتظر... + Free + 1:1 + 3:4 + 2:1 + 16:9 + 1:2 + 4:3 + 9:16 + 3:2 + 2:3 \ No newline at end of file diff --git a/gallerylib/src/main/res/values/colors.xml b/gallerylib/src/main/res/values/colors.xml index bcdaaa6..6f9060c 100644 --- a/gallerylib/src/main/res/values/colors.xml +++ b/gallerylib/src/main/res/values/colors.xml @@ -1,276 +1,287 @@ - #2bdfcc - #2bdfcc - #04A192 - #3a3a3a - #555555 - #000000 - #4b4b4b - #ffffff - #2bdfcc - #6f7b87 - #26007FFF - #55d160 - #b7b7b7 - #4fa5c4 - #6f7bb7 - #77E8EDEF - #d8d8d8 - #121212 - #0d0d62 - #ff0000 - #FF98CADC - #aa2bdfcc - #162bdfcc - #3B2bdfcc - #482bdfcc - #16797979 - #3B797979 - #48797979 - #b4b4b4 - #174f62 - #173d51 - #f46c69 - #FFE8EDEF - #797979 - #424242 - #bad0b8 - #ea5554 - #dedede - #f3f6f7 - #979797 - #e8e8e8 - #ef5357 - #3bb298 - #9a9a9a - #e5e5e5 - #d2d2d2 - #268ac2 - #d8d8d8 - #737373 - #dbdbdb - #efefef - #636363 - #dbc7cc - #660d24 - #061524 - #190712 - #dadada - #2c2c2c - #9b9b9b - #f5a623 - #f8e71c - #8b572a - #d0021b - #7ed321 - #417505 - #bd10e0 - #4a90e2 - #50e3c2 - #b8e986 - #4a4a4a - #346b46 - #181951 - #4704d3 - #adca14 - #d07014 - #17cedd - #af132f - #003307 - #0030ef - #cfcfcf - #a7a7a7 - #3c58bf - #293688 - #051244 - #263b80 - #139ad6 - #232c65 - #ffbc00 - #f7981d - #ed7c00 - #ededed - #00000000 - #FFF5F5F5 - #FFEDBD1C - #ED9000 - #f8f8f8 - #ebebeb - #cacacc - #2a94e2 - #6633B5E5 - #3B5998 - #77ffffff - #ccffffff - #77cacacc - #33cacacc - #ff3333 - #BB000000 - #88000000 - #eac14d - #b7ce62 - #82d6b5 - #9982d6b5 - #52d0c5 - #424242 - #fa8c73 - #ff3368 - #d95757 - #FFD0021B - #C7C7C7 - #003366 - #003366 - #003366 - #003366 - #333333 - #1c1421 - #5A1c1421 - #542a45 - #5A542a45 - #6699FF - #808080 - #475461 - #efefef - #d95757 - #bfbfbf - #000015 - #44000000 - #336666 - #e33d1b - #e26d0e - #FFCC33 - #fe8019 - #0de9dd - #36d936 - #cc00ff - #00fff1 - #fef200 - #B0E0E6 - #37d219 - #90caf9 - #d55959 - #1976d2 - #551976d2 - #351976d2 - #202020 - #1965aa - #dc5050 - #fafafa - #0b9af5 - #eaf4fb - #cae5f7 - #eaf6ff - #FF8CBAE8 - #646464 - #48646464 - #d2d2d2 - #EEEEEE - #e04242 - #aeaeae - #99aeaeae - #fcdc8b - #f7b753 - #aaf7b753 - #07488a - #117ebe - #787878 - #000002 - #d59e47 - #4084c1 - #FFD59E47 - #aaC6A04A - #d0283d - #e99d42 - #a0a0a0 - #cbca00 - #d9e1e0 - #2bf5e0 - #0efc0c - #0CB450 + #2bdfcc + #2bdfcc + #04A192 + #3a3a3a + #555555 + #000000 + #4b4b4b + #ffffff + #2bdfcc + #6f7b87 + #26007FFF + #55d160 + #b7b7b7 + #4fa5c4 + #6f7bb7 + #77E8EDEF + #d8d8d8 + #121212 + #0d0d62 + #ff0000 + #FF98CADC + #aa2bdfcc + #162bdfcc + #3B2bdfcc + #482bdfcc + #16797979 + #3B797979 + #48797979 + #b4b4b4 + #174f62 + #173d51 + #f46c69 + #FFE8EDEF + #797979 + #424242 + #bad0b8 + #ea5554 + #dedede + #f3f6f7 + #979797 + #e8e8e8 + #ef5357 + #3bb298 + #9a9a9a + #e5e5e5 + #d2d2d2 + #268ac2 + #d8d8d8 + #737373 + #dbdbdb + #efefef + #636363 + #dbc7cc + #660d24 + #061524 + #190712 + #dadada + #2c2c2c + #9b9b9b + #f5a623 + #f8e71c + #8b572a + #d0021b + #7ed321 + #417505 + #bd10e0 + #4a90e2 + #50e3c2 + #b8e986 + #4a4a4a + #346b46 + #181951 + #4704d3 + #adca14 + #d07014 + #17cedd + #af132f + #003307 + #0030ef + #cfcfcf + #a7a7a7 + #3c58bf + #293688 + #051244 + #263b80 + #139ad6 + #232c65 + #ffbc00 + #f7981d + #ed7c00 + #ededed + #00000000 + #FFF5F5F5 + #FFEDBD1C + #ED9000 + #f8f8f8 + #ebebeb + #cacacc + #2a94e2 + #6633B5E5 + #3B5998 + #77ffffff + #ccffffff + #77cacacc + #33cacacc + #ff3333 + #BB000000 + #88000000 + #eac14d + #b7ce62 + #82d6b5 + #9982d6b5 + #52d0c5 + #424242 + #fa8c73 + #ff3368 + #d95757 + #FFD0021B + #C7C7C7 + #003366 + #003366 + #003366 + #003366 + #333333 + #1c1421 + #5A1c1421 + #542a45 + #5A542a45 + #6699FF + #808080 + #475461 + #efefef + #d95757 + #bfbfbf + #000015 + #44000000 + #336666 + #e33d1b + #e26d0e + #FFCC33 + #fe8019 + #0de9dd + #36d936 + #cc00ff + #00fff1 + #fef200 + #B0E0E6 + #37d219 + #90caf9 + #d55959 + #1976d2 + #551976d2 + #351976d2 + #202020 + #1965aa + #dc5050 + #fafafa + #0b9af5 + #eaf4fb + #cae5f7 + #eaf6ff + #FF8CBAE8 + #646464 + #48646464 + #d2d2d2 + #EEEEEE + #e04242 + #aeaeae + #99aeaeae + #fcdc8b + #f7b753 + #aaf7b753 + #07488a + #117ebe + #787878 + #000002 + #d59e47 + #4084c1 + #FFD59E47 + #aaC6A04A + #d0283d + #e99d42 + #a0a0a0 + #cbca00 + #d9e1e0 + #2bf5e0 + #0efc0c + #0CB450 + + #009b5d + #ffdc67 + #fc2895 + #dadbdc + #aaccdd + #bab900 + #1c003d + #b81a6b + #fffe04 + #b7c7ca + #1dc0af + #fdb848 + #d0cf00 + #29dac8 + #b7b700 + #00bff3 + #d5d500 + #e3e200 + #20ccba + #d1d100 + #c6c500 + #c21e72 + #fdc26d + #f05164 + #00bcf2 + #bad2de + #35175d + #a82aff + #3978bd + #f4805c + #c1da68 + #4cab66 + #d08bff + #91d9f8 + #6ea5be + #3f6e82 + #ab3f52 + #79c695 + #c1e8f8 + #f6a2b2 + #155b85 + #22d2c0 + #d1d3d4 + #29995d + #d01f7a + #d91f7e + #be1e2d + #ef435a + #6e7682 + #939598 + #e4f5fd + #c9d9e1 + #c4e9fb + #0bbe09 + #f73859 + #6d6d6d + #e02020 + #1cb8a8 + #7E57C2 + #5C6AC0 + #AA47BC + #F9A827 + #EE534F + #66BB6A + #EB407A + #FEEE58 + #E43935 + #aa1cb8a8 + #aa7E57C2 + #aa5C6AC0 + #aaAA47BC + #aaF9A827 + #aaEE534F + #aa66BB6A + #aaEB407A + #aaFEEE58 + #aaE43935 + #3cb899 + #555a65 + #e7a870 + #277864 + #ffeaea + #EEF7FF + + #20242F + #FF6300 + #000 + + #FF6300 + #20242F + #B3BECE + + - #009b5d - #ffdc67 - #fc2895 - #dadbdc - #aaccdd - #bab900 - #1c003d - #b81a6b - #fffe04 - #b7c7ca - #1dc0af - #fdb848 - #d0cf00 - #29dac8 - #b7b700 - #00bff3 - #d5d500 - #e3e200 - #20ccba - #d1d100 - #c6c500 - #c21e72 - #fdc26d - #f05164 - #00bcf2 - #bad2de - #35175d - #a82aff - #3978bd - #f4805c - #c1da68 - #4cab66 - #d08bff - #91d9f8 - #6ea5be - #3f6e82 - #ab3f52 - #79c695 - #c1e8f8 - #f6a2b2 - #155b85 - #22d2c0 - #d1d3d4 - #29995d - #d01f7a - #d91f7e - #be1e2d - #ef435a - #6e7682 - #939598 - #e4f5fd - #c9d9e1 - #c4e9fb - #0bbe09 - #f73859 - #6d6d6d - #e02020 - #1cb8a8 - #7E57C2 - #5C6AC0 - #AA47BC - #F9A827 - #EE534F - #66BB6A - #EB407A - #FEEE58 - #E43935 - #aa1cb8a8 - #aa7E57C2 - #aa5C6AC0 - #aaAA47BC - #aaF9A827 - #aaEE534F - #aa66BB6A - #aaEB407A - #aaFEEE58 - #aaE43935 - #3cb899 - #555a65 - #e7a870 - #277864 - #ffeaea - #EEF7FF diff --git a/gallerylib/src/main/res/values/strings.xml b/gallerylib/src/main/res/values/strings.xml index 07a6612..2643556 100644 --- a/gallerylib/src/main/res/values/strings.xml +++ b/gallerylib/src/main/res/values/strings.xml @@ -20,4 +20,14 @@ Settings You can\'t select more than %s item Please wait... + Free + 1:1 + 3:4 + 2:1 + 16:9 + 1:2 + 4:3 + 9:16 + 3:2 + 2:3 \ No newline at end of file