diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MediaActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MediaActivity.kt index 5e4dde7f1..5be201374 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MediaActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MediaActivity.kt @@ -56,7 +56,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener { mIsGetAnyIntent = getBooleanExtra(GET_ANY_INTENT, false) } - media_holder.setOnRefreshListener({ getMedia() }) + media_refresh_layout.setOnRefreshListener({ getMedia() }) mPath = intent.getStringExtra(DIRECTORY) mStoredAnimateGifs = config.animateGifs mShowAll = config.showAll @@ -76,7 +76,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener { super.onPause() mCurrAsyncTask?.shouldStop = true mIsGettingMedia = false - media_holder.isRefreshing = false + media_refresh_layout.isRefreshing = false mStoredAnimateGifs = config.animateGifs } @@ -105,6 +105,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener { } else { media_grid.adapter = adapter } + media_fastscroller.setViews(media_grid, media_refresh_layout) } override fun onCreateOptionsMenu(menu: Menu): Boolean { @@ -214,7 +215,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener { val token = object : TypeToken>() {}.type val media = Gson().fromJson>(config.loadFolderMedia(mPath), token) ?: ArrayList(1) if (media.size == 0) { - media_holder.isRefreshing = true + media_refresh_layout.isRefreshing = true } else { if (!mLoadedInitialPhotos) gotMedia(media) @@ -339,7 +340,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener { fun gotMedia(media: ArrayList) { mIsGettingMedia = false - media_holder.isRefreshing = false + media_refresh_layout.isRefreshing = false if (media.hashCode() == mMedia.hashCode()) return diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/views/FastScroller.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/views/FastScroller.kt new file mode 100644 index 000000000..0bc825499 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/views/FastScroller.kt @@ -0,0 +1,121 @@ +package com.simplemobiletools.gallery.views + +import android.content.Context +import android.support.v4.widget.SwipeRefreshLayout +import android.support.v7.widget.GridLayoutManager +import android.support.v7.widget.RecyclerView +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.MotionEvent +import android.view.View +import android.widget.LinearLayout +import com.simplemobiletools.gallery.R +import kotlinx.android.synthetic.main.fastscroller.view.* + +// based on https://blog.stylingandroid.com/recyclerview-fastscroll-part-1 +class FastScroller : LinearLayout { + private val handle: View + private var currHeight = 0 + + private val HANDLE_HIDE_DELAY = 1000L + private var recyclerView: RecyclerView? = null + private var swipeRefreshLayout: SwipeRefreshLayout? = null + + constructor(context: Context) : super(context) + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) + + constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) + + fun setViews(recyclerView: RecyclerView, swipeRefreshLayout: SwipeRefreshLayout) { + this.recyclerView = recyclerView + this.swipeRefreshLayout = swipeRefreshLayout + + recyclerView.setOnScrollListener(object : RecyclerView.OnScrollListener() { + override fun onScrolled(rv: RecyclerView, dx: Int, dy: Int) { + updateHandlePosition() + } + + override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { + super.onScrollStateChanged(recyclerView, newState) + if (newState == RecyclerView.SCROLL_STATE_DRAGGING) { + showHandle() + } else if (newState == RecyclerView.SCROLL_STATE_IDLE) { + hideHandle() + } + } + }) + } + + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + currHeight = h + updateHandlePosition() + } + + private fun updateHandlePosition() { + if (handle.isSelected) + return + + val verticalScrollOffset = recyclerView!!.computeVerticalScrollOffset() + val verticalScrollRange = recyclerView!!.computeVerticalScrollRange() + val proportion = verticalScrollOffset.toFloat() / (verticalScrollRange.toFloat() - currHeight) + setPosition(currHeight * proportion) + } + + override fun onTouchEvent(event: MotionEvent): Boolean { + return when (event.action) { + MotionEvent.ACTION_DOWN -> { + showHandle() + handle.isSelected = true + swipeRefreshLayout?.isEnabled = false + true + } + MotionEvent.ACTION_MOVE -> { + setPosition(event.y) + setRecyclerViewPosition(event.y) + true + } + MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { + hideHandle() + handle.isSelected = false + swipeRefreshLayout?.isEnabled = true + true + } + else -> super.onTouchEvent(event) + } + } + + private fun setRecyclerViewPosition(y: Float) { + if (recyclerView != null) { + val itemCount = recyclerView!!.adapter.itemCount + val proportion = y / currHeight + val targetPos = getValueInRange(0f, (itemCount - 1).toFloat(), proportion * itemCount).toInt() + (recyclerView!!.layoutManager as GridLayoutManager).scrollToPositionWithOffset(targetPos, 0) + } + } + + init { + orientation = LinearLayout.HORIZONTAL + clipChildren = false + val inflater = LayoutInflater.from(context) + inflater.inflate(R.layout.fastscroller, this) + handle = fastscroller_handle + } + + private fun showHandle() { + handle.animate().alpha(1f).startDelay = 0L + } + + private fun hideHandle() { + handle.animate().alpha(0f).startDelay = HANDLE_HIDE_DELAY + } + + private fun setPosition(y: Float) { + val position = y / currHeight + val handleHeight = handle.height + handle.y = getValueInRange(0f, (currHeight - handleHeight).toFloat(), (currHeight - handleHeight) * position) + } + + private fun getValueInRange(min: Float, max: Float, value: Float) = Math.min(Math.max(min, value), max) +} diff --git a/app/src/main/res/drawable/fastscroller_handle.xml b/app/src/main/res/drawable/fastscroller_handle.xml new file mode 100644 index 000000000..d03cbde11 --- /dev/null +++ b/app/src/main/res/drawable/fastscroller_handle.xml @@ -0,0 +1,13 @@ + + + + + + + + + diff --git a/app/src/main/res/layout/activity_media.xml b/app/src/main/res/layout/activity_media.xml index 5f50f279b..9e235bfab 100644 --- a/app/src/main/res/layout/activity_media.xml +++ b/app/src/main/res/layout/activity_media.xml @@ -2,16 +2,31 @@ - + android:layout_height="wrap_content"> + + + + + diff --git a/app/src/main/res/layout/fastscroller.xml b/app/src/main/res/layout/fastscroller.xml new file mode 100644 index 000000000..48c83bd80 --- /dev/null +++ b/app/src/main/res/layout/fastscroller.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 035ba3688..f9bfd2df7 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -8,4 +8,6 @@ 24dp 50dp 48dp + 8dp + 40dp