Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/dev'
Browse files Browse the repository at this point in the history
# Conflicts:
#	file-picker/build.gradle
  • Loading branch information
Majid Arabi committed Aug 28, 2022
2 parents 0ba9f2c + d382205 commit 27dbc34
Show file tree
Hide file tree
Showing 16 changed files with 229 additions and 78 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import androidx.core.net.toUri
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.github.file_picker.model.Media
import com.github.file_picker.data.model.Media
import ir.one_developer.filepickerlibrary.databinding.FileLayoutBinding
import java.io.File

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import com.github.file_picker.adapter.FilePickerAdapter
import com.github.file_picker.extension.showFilePicker
import com.github.file_picker.listener.OnItemClickListener
import com.github.file_picker.listener.OnSubmitClickListener
import com.github.file_picker.model.Media
import com.github.file_picker.data.model.Media
import ir.one_developer.filepickerlibrary.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {
Expand Down Expand Up @@ -65,6 +65,7 @@ class MainActivity : AppCompatActivity() {
limitItemSelection = limit,
gridSpanCount = spanCount,
selectedFiles = selectedFiles,
overlayAlpha = 0.75f,
accentColor = ContextCompat.getColor(this@MainActivity, accentColor),
titleTextColor = ContextCompat.getColor(this@MainActivity, accentColor),
onSubmitClickListener = object : OnSubmitClickListener {
Expand Down
24 changes: 18 additions & 6 deletions file-picker/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,32 @@ android {
}

dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.core:core-ktx:1.8.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'com.google.android.material:material:1.6.1'

// Coroutines
def coroutine_version = "1.6.0"
def activity_version = "1.5.1"
implementation "androidx.activity:activity-ktx:$activity_version"

def fragment_version = "1.5.2"
implementation "androidx.fragment:fragment-ktx:$fragment_version"

def coroutine_version = "1.6.1"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutine_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutine_version"

// Glide
def glide_version = "4.13.0"
implementation "com.github.bumptech.glide:glide:$glide_version"
annotationProcessor "com.github.bumptech.glide:compiler:$glide_version"

def paging_version = "3.1.1"
implementation "androidx.paging:paging-runtime:$paging_version"

def lifecycle_version = "2.5.1"
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
}

afterEvaluate {
Expand All @@ -58,7 +70,7 @@ afterEvaluate {
from components.release
groupId = 'com.github.majidarabi'
artifactId = 'file-picker'
version = '0.1.0'
version = '0.0.9'
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion file-picker/src/main/java/com/github/file_picker/Const.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ enum class FileType : Parcelable {
VIDEO,
IMAGE,
AUDIO,
}
}

const val PAGE_SIZE = 10
62 changes: 38 additions & 24 deletions file-picker/src/main/java/com/github/file_picker/FilePicker.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,19 @@ import android.view.View
import android.view.ViewGroup
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.ColorInt
import androidx.annotation.FloatRange
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import androidx.fragment.app.FragmentManager
import androidx.paging.LoadState
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.github.file_picker.adapter.ItemAdapter
import com.github.file_picker.extension.getStorageFiles
import com.github.file_picker.data.model.Media
import com.github.file_picker.data.repository.FilesRepository
import com.github.file_picker.extension.hasPermission
import com.github.file_picker.listener.OnItemClickListener
import com.github.file_picker.listener.OnSubmitClickListener
import com.github.file_picker.model.Media
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
Expand Down Expand Up @@ -49,6 +51,7 @@ class FilePicker private constructor(
private var _binding: FilePickerBinding? = null

private var itemsAdapter: ItemAdapter? = null
private lateinit var repository: FilesRepository

private var title: String
private var titleTextColor by Delegates.notNull<Int>()
Expand All @@ -61,6 +64,7 @@ class FilePicker private constructor(
private var accentColor by Delegates.notNull<Int>()
private var gridSpanCount by Delegates.notNull<Int>()
private var cancellable by Delegates.notNull<Boolean>()
private var overlayAlpha by Delegates.notNull<Float>()

private var onItemClickListener: OnItemClickListener?
private var onSubmitClickListener: OnSubmitClickListener?
Expand All @@ -77,6 +81,7 @@ class FilePicker private constructor(
this.gridSpanCount = builder.gridSpanCount
this.limitCount = builder.limitCount
this.accentColor = builder.accentColor
this.overlayAlpha = builder.overlayAlpha
this.onItemClickListener = builder.onItemClickListener
this.onSubmitClickListener = builder.onSubmitClickListener
}
Expand Down Expand Up @@ -116,6 +121,8 @@ class FilePicker private constructor(
private set
var onSubmitClickListener: OnSubmitClickListener? = null
private set
var overlayAlpha: Float = DEFAULT_OVERLAY_ALPHA
private set

/**
* Set title
Expand Down Expand Up @@ -228,14 +235,21 @@ class FilePicker private constructor(
) = apply { this.onItemClickListener = onItemClickListener }

/**
* Build file picker instance
* Set overlay alpha
*
* @param alpha
*/
fun setOverlayAlpha(
alpha: Float
) = apply { this.overlayAlpha = alpha }

/**
* Build file picker instance
*/
fun build() = FilePicker(this)

/**
* Build file picker and show it
*
*/
fun buildAndShow() = build().show(
appCompatActivity.supportFragmentManager,
Expand All @@ -257,6 +271,7 @@ class FilePicker private constructor(
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
repository = FilesRepository(requireActivity().application)
setCancellableDialog(cancellable)
setupViews()
}
Expand Down Expand Up @@ -365,6 +380,7 @@ class FilePicker private constructor(
private fun setupRecyclerView(recyclerView: RecyclerView) {
itemsAdapter = ItemAdapter(
accentColor = accentColor,
overlayAlpha = overlayAlpha,
limitSelectionCount = limitCount,
listener = { itemPosition ->
setupOnItemClickListener(itemPosition)
Expand All @@ -390,7 +406,7 @@ class FilePicker private constructor(
private fun setupOnItemClickListener(position: Int) {
if (onItemClickListener == null) return
if (itemsAdapter == null) return
val media = itemsAdapter?.currentList?.get(position) ?: return
val media = itemsAdapter?.snapshot()?.items?.get(position) ?: return
onItemClickListener?.onClick(media, position, itemsAdapter!!)
}

Expand All @@ -411,34 +427,29 @@ class FilePicker private constructor(

/**
* Load files
*
*/
private fun loadFiles() = CoroutineScope(Dispatchers.IO).launch {
val files = getStorageFiles(fileType = fileType)
.map { Media(file = it, type = fileType) }

if (selectedFiles.isNotEmpty()) {
selectedFiles.forEach { media ->
val selectedMedia = files.find { it.id == media.id }
if (selectedMedia != null) {
selectedMedia.isSelected = media.isSelected
selectedMedia.order = media.order
itemsAdapter?.addLoadStateListener { state ->
binding.progress.isVisible = state.source.refresh is LoadState.Loading
if (state.source.refresh is LoadState.NotLoading) {
selectedFiles.forEach { media ->
itemsAdapter?.snapshot()?.items?.find { it.id == media.id }?.let {
it.isSelected = media.isSelected
it.order = media.order
}
}
updateSelectedCount()
setFixedSubmitButton()
changeSubmitButtonState()
}
}

requireActivity().runOnUiThread {
itemsAdapter?.submitList(files)
updateSelectedCount()
setFixedSubmitButton()
changeSubmitButtonState()
binding.progress.isVisible = false
repository.getFiles(fileType = fileType).collect { pagingData ->
itemsAdapter?.submitData(pagingData)
}
}

/**
* Submit list
*
*/
private fun submitList() = getSelectedItems()?.let {
onSubmitClickListener?.onClick(it)
Expand All @@ -450,7 +461,7 @@ class FilePicker private constructor(
* @return
*/
private fun getSelectedItems(): List<Media>? =
itemsAdapter?.currentList?.filter { it.isSelected }?.sortedBy { it.order }
itemsAdapter?.snapshot()?.items?.filter { it.isSelected }?.sortedBy { it.order }

/**
* Has selected item
Expand All @@ -471,6 +482,9 @@ class FilePicker private constructor(
const val DEFAULT_TITLE = "Choose File"
const val DEFAULT_TITLE_TEXT_COLOR = DEFAULT_ACCENT_COLOR

@FloatRange(from = 0.0, to = 1.0)
const val DEFAULT_OVERLAY_ALPHA = 0.5F

const val DEFAULT_SUBMIT_TEXT = "Submit"
const val DEFAULT_SUBMIT_TEXT_COLOR = Color.WHITE

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,26 @@ package com.github.file_picker.adapter

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.paging.PagingDataAdapter
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import com.github.file_picker.FilePicker
import com.github.file_picker.extension.isValidPosition
import com.github.file_picker.model.Media
import com.github.file_picker.data.model.Media
import ir.one_developer.file_picker.databinding.ItemLayoutBinding
import java.util.Locale.filter

internal class ItemAdapter(
private var accentColor: Int = FilePicker.DEFAULT_ACCENT_COLOR,
private var overlayAlpha: Float = FilePicker.DEFAULT_OVERLAY_ALPHA,
private var limitSelectionCount: Int = FilePicker.DEFAULT_LIMIT_COUNT,
private var listener: ((Int) -> Unit)? = null
) : ListAdapter<Media, ItemVH>(COMPARATOR), FilePickerAdapter {
) : PagingDataAdapter<Media, ItemVH>(COMPARATOR), FilePickerAdapter {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemVH(
listener = listener,
accentColor = accentColor,
overlayAlpha =overlayAlpha,
limitSelectionCount = limitSelectionCount,
binding = ItemLayoutBinding.inflate(
LayoutInflater.from(parent.context),
Expand All @@ -27,7 +31,7 @@ internal class ItemAdapter(
)

override fun onBindViewHolder(holder: ItemVH, position: Int) {
holder.bind(getItem(position))
getItem(position)?.let { holder.bind(it) }
}

/**
Expand All @@ -37,8 +41,8 @@ internal class ItemAdapter(
*/
override fun setSelected(position: Int) {
if (limitSelectionCount > 1) {
val item = getItem(position)
val selectedItems = currentList.filter { it.isSelected && it.id != item.id }
val item = getItem(position) ?: return
val selectedItems = snapshot().items.filter { it.isSelected && it.id != item.id }
val selectedItemCount = selectedItems.size

if (item.isSelected) {
Expand All @@ -47,7 +51,7 @@ internal class ItemAdapter(
selectedItems.forEach { media ->
if (media.order > item.order) {
media.order--
notifyItemChanged(currentList.indexOf(media))
notifyItemChanged(snapshot().items.indexOf(media))
}
}
return
Expand All @@ -61,22 +65,16 @@ internal class ItemAdapter(
return
}

if (!currentList.isValidPosition(lastSelectedPosition)) {
if (!snapshot().items.isValidPosition(lastSelectedPosition)) {
lastSelectedPosition = position
}
getItem(lastSelectedPosition).isSelected = false
getItem(lastSelectedPosition)?.isSelected = false
notifyItemChanged(lastSelectedPosition)
lastSelectedPosition = position
getItem(lastSelectedPosition).isSelected = true
getItem(lastSelectedPosition)?.isSelected = true
notifyItemChanged(lastSelectedPosition)
}

override fun setHasStableIds(hasStableIds: Boolean) {
super.setHasStableIds(true)
}

override fun getItemId(position: Int): Long = getItem(position).id.toLong()

companion object {
private var lastSelectedPosition = -1

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,25 @@ import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import com.github.file_picker.FileType
import com.github.file_picker.data.model.Media
import com.github.file_picker.extension.getMusicCoverArt
import com.github.file_picker.extension.lastPathTitle
import com.github.file_picker.extension.size
import com.github.file_picker.model.Media
import ir.one_developer.file_picker.R
import ir.one_developer.file_picker.databinding.ItemLayoutBinding

internal class ItemVH(
private val listener: ((Int) -> Unit)?,
private val binding: ItemLayoutBinding,
private val accentColor: Int,
private val overlayAlpha: Float,
private val limitSelectionCount: Int
) : RecyclerView.ViewHolder(binding.root) {

init {
binding.apply {
frameChecked.setBackgroundColor(accentColor)
frameChecked.alpha = overlayAlpha
card.setOnClickListener {
listener?.invoke(bindingAdapterPosition)
}
Expand Down Expand Up @@ -63,7 +65,7 @@ internal class ItemVH(

Glide.with(ivImage)
.load(previewImage)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.transition(DrawableTransitionOptions.withCrossFade())
.listener(object : RequestListener<Drawable> {
override fun onLoadFailed(
Expand All @@ -82,20 +84,18 @@ internal class ItemVH(
target: Target<Drawable>?,
dataSource: DataSource?,
isFirstResource: Boolean
): Boolean {
return false
}

): Boolean = false
})
.into(ivImage)
}

private fun setErrorState(type: FileType) = binding.apply {
cardErrorState.isVisible = true
when (type) {
FileType.AUDIO -> ivErrorIcon.setImageResource(R.drawable.ic_audiotrack)
FileType.IMAGE -> ivErrorIcon.setImageResource(R.drawable.ic_image)
FileType.VIDEO -> ivErrorIcon.setImageResource(R.drawable.ic_play)
FileType.VIDEO -> Glide.with(ivErrorIcon).load(R.drawable.ic_play).into(ivErrorIcon)
FileType.IMAGE -> Glide.with(ivErrorIcon).load(R.drawable.ic_image).into(ivErrorIcon)
FileType.AUDIO -> Glide.with(ivErrorIcon).load(R.drawable.ic_audiotrack)
.into(ivErrorIcon)
}
}

Expand Down
Loading

0 comments on commit 27dbc34

Please sign in to comment.