Skip to content

Commit

Permalink
Merge pull request #986 from mikepenz/develop
Browse files Browse the repository at this point in the history
dev -> main
  • Loading branch information
mikepenz committed Mar 17, 2021
2 parents a31bfaf + 246bd64 commit 72631f2
Show file tree
Hide file tree
Showing 24 changed files with 672 additions and 59 deletions.
18 changes: 11 additions & 7 deletions Gemfile.lock
Expand Up @@ -4,7 +4,7 @@ GEM
addressable (2.7.0)
public_suffix (>= 2.0.2, < 5.0)
ansi (1.5.0)
ast (2.4.1)
ast (2.4.2)
claide (1.0.3)
claide-plugins (0.9.2)
cork
Expand All @@ -13,7 +13,7 @@ GEM
colored2 (3.1.2)
cork (0.3.0)
colored2 (~> 3.1)
danger (8.0.6)
danger (8.2.3)
claide (~> 1.0)
claide-plugins (>= 0.9.2)
colored2 (~> 3.1)
Expand All @@ -25,19 +25,22 @@ GEM
kramdown-parser-gfm (~> 1.0)
no_proxy_fix
octokit (~> 4.7)
terminal-table (~> 1)
terminal-table (>= 1, < 4)
danger-android_lint (0.0.8)
danger-plugin-api (~> 1.0)
oga
danger-kotlin_detekt (0.0.3)
danger-plugin-api (~> 1.0)
danger-plugin-api (1.0.0)
danger (> 2.0)
faraday (1.0.1)
faraday (1.3.0)
faraday-net_http (~> 1.0)
multipart-post (>= 1.2, < 3)
ruby2_keywords
faraday-http-cache (2.2.0)
faraday (>= 0.8)
git (1.7.0)
faraday-net_http (1.0.1)
git (1.8.1)
rchardet (~> 1.8)
kramdown (2.3.0)
rexml
Expand All @@ -46,7 +49,7 @@ GEM
multipart-post (2.1.1)
nap (1.1.0)
no_proxy_fix (0.1.2)
octokit (4.18.0)
octokit (4.20.0)
faraday (>= 0.9)
sawyer (~> 0.8.0, >= 0.5.3)
oga (3.3)
Expand All @@ -59,10 +62,11 @@ GEM
ruby-ll (2.1.2)
ansi
ast
ruby2_keywords (0.0.4)
sawyer (0.8.2)
addressable (>= 2.3.5)
faraday (> 0.8, < 2.0)
terminal-table (1.8.0)
terminal-table (3.0.0)
unicode-display_width (~> 1.1, >= 1.1.1)
unicode-display_width (1.7.0)

Expand Down
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -48,6 +48,7 @@ It's blazing fast, minimizing the code you need to write, and is easy to extend.

## Latest releases 🛠

- Kotlin Beta | [v5.4.0-b01](https://github.com/mikepenz/FastAdapter/tree/v5.4.0-b01)
- Kotlin | [v5.3.5](https://github.com/mikepenz/FastAdapter/tree/v5.3.5)
- Java && AndroidX | [v3.3.1](https://github.com/mikepenz/FastAdapter/tree/v3.3.1)
- Java && AppCompat | [v3.2.9](https://github.com/mikepenz/FastAdapter/tree/v3.2.9)
Expand Down
15 changes: 2 additions & 13 deletions app/src/main/AndroidManifest.xml
Expand Up @@ -88,19 +88,8 @@
<activity
android:name="com.mikepenz.fastadapter.app.DiffUtilActivity"
android:label="@string/sample_diff_util" />

<!-- USED FOR THE MopubAdsActivity sample-->
<activity
android:name="com.mopub.common.MoPubBrowser"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name="com.mopub.mobileads.MoPubActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name="com.mopub.mobileads.MraidActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name="com.mopub.mobileads.MraidVideoPlayerActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
android:name="com.mikepenz.fastadapter.app.DragAndDropActivity"
android:label="Drag &amp; Drop Sample" />
</application>
</manifest>
208 changes: 208 additions & 0 deletions app/src/main/java/com/mikepenz/fastadapter/app/DragAndDropActivity.kt
@@ -0,0 +1,208 @@
package com.mikepenz.fastadapter.app

import android.os.Bundle
import android.view.MenuItem
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.res.ResourcesCompat
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.mikepenz.fastadapter.FastAdapter
import com.mikepenz.fastadapter.GenericItem
import com.mikepenz.fastadapter.IAdapter
import com.mikepenz.fastadapter.adapters.ItemAdapter
import com.mikepenz.fastadapter.adapters.ItemAdapter.Companion.items
import com.mikepenz.fastadapter.app.databinding.ActivitySampleBinding
import com.mikepenz.fastadapter.app.items.DragHandleTouchEvent
import com.mikepenz.fastadapter.app.items.DraggableSingleLineItem
import com.mikepenz.fastadapter.app.items.SectionHeaderItem
import com.mikepenz.fastadapter.app.items.SmallIconSingleLineItem
import com.mikepenz.fastadapter.app.view.DraggableFrameLayout
import com.mikepenz.fastadapter.app.view.RecyclerViewBackgroundDrawable
import com.mikepenz.fastadapter.drag.ItemTouchCallback
import com.mikepenz.fastadapter.drag.SimpleDragCallback
import com.mikepenz.fastadapter.utils.DragDropUtil
import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.materialdesigniconic.MaterialDesignIconic

private const val STATE_LIST_ORDER = "com.mikepenz.fastadapter.app.LIST_ORDER"

class DragAndDropActivity : AppCompatActivity(), ItemTouchCallback {
private lateinit var binding: ActivitySampleBinding

private lateinit var fastAdapter: FastAdapter<GenericItem>
private lateinit var itemAdapter: ItemAdapter<GenericItem>

private lateinit var touchCallback: SimpleDragCallback
private lateinit var touchHelper: ItemTouchHelper

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivitySampleBinding.inflate(layoutInflater).also {
setContentView(it.root)
}

setSupportActionBar(binding.toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setHomeButtonEnabled(false)

// Create empty ItemAdapter
itemAdapter = items()

// Create FastAdapter instance that will manage the whole list
fastAdapter = FastAdapter.with(itemAdapter).apply {
// Add an event hook that manages touching the drag handle
addEventHook(
DragHandleTouchEvent { position ->
binding.rv.findViewHolderForAdapterPosition(position)?.let { viewHolder ->
// Start dragging
touchHelper.startDrag(viewHolder)
}
}
)
}

// Handle clicks on our list items
fastAdapter.onClickListener = { v: View?, _: IAdapter<GenericItem>, item: GenericItem, _: Int ->
if (v != null) {
// Perform an action depending on the type of the item
val message = when (item) {
is SmallIconSingleLineItem -> item.name.getText(v.context)
is DraggableSingleLineItem -> item.name.getText(v.context)
is SectionHeaderItem -> null
else -> "Unknown item type: $item"
}
if (message != null) {
Toast.makeText(v.context, message, Toast.LENGTH_SHORT).show()
}
}
false
}

// Set up our RecyclerView
binding.rv.layoutManager = LinearLayoutManager(this)
binding.rv.itemAnimator = DefaultItemAnimator()
binding.rv.adapter = fastAdapter

// Set a custom background on the RecyclerView. It avoids filling the area without list items at the bottom of
// the RecyclerView with our background color.
val recyclerViewBackgroundColor = ResourcesCompat.getColor(resources, R.color.behindRecyclerView, theme)
RecyclerViewBackgroundDrawable(recyclerViewBackgroundColor).attachTo(binding.rv)

// Create our list and set it on the adapter
val items = buildSampleItemList(savedInstanceState)
itemAdapter.add(items)

// Add drag and drop functionality to the RecyclerView
touchCallback = SimpleDragCallback(itemTouchCallback = this).apply {
// Disable drag & drop on long-press
isDragEnabled = false
}
touchHelper = ItemTouchHelper(touchCallback)
touchHelper.attachToRecyclerView(binding.rv)

// Restore the adapter state (this has to be done after adding the items)
fastAdapter.withSavedInstanceState(savedInstanceState)
}

private fun buildSampleItemList(savedInstanceState: Bundle?): ArrayList<GenericItem> {
val items = ArrayList<GenericItem>()
items.add(
SmallIconSingleLineItem(
IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_settings),
getString(R.string.list_item_general_settings)
)
)

items.add(SectionHeaderItem(getString(R.string.list_item_accounts_section)))

val accountIcon = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_account)

val accountItems = (1..5).map { i ->
val name = getString(R.string.list_item_account, i)
DraggableSingleLineItem(accountIcon, name).apply {
identifier = (100 + i).toLong()
}
}

// Use the saved state (if available) to sort the list of accounts
val sortedAccountItems = if (savedInstanceState != null) {
val listOrder = savedInstanceState.getLongArray(STATE_LIST_ORDER) ?: error("Missing saved state")
val orderById = listOrder.withIndex().associate { it.value to it.index }
accountItems.sortedBy { orderById[it.identifier] }
} else {
accountItems
}

items.addAll(sortedAccountItems)

items.add(SectionHeaderItem(getString(R.string.list_item_misc_section)))
items.add(SmallIconSingleLineItem(
IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_info),
getString(R.string.list_item_about)
))
items.add(
SmallIconSingleLineItem(
IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_code),
getString(R.string.list_item_licenses)
)
)
return items
}

override fun onSaveInstanceState(outState: Bundle) {
// Save the adapter's state
val newOutState = fastAdapter.saveInstanceState(outState)

// Save the current account order
val itemIdentifiers = itemAdapter.adapterItems
.filterIsInstance<DraggableSingleLineItem>()
.map { it.identifier }
.toLongArray()
newOutState.putLongArray(STATE_LIST_ORDER, itemIdentifiers)

super.onSaveInstanceState(newOutState)
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
android.R.id.home -> {
onBackPressed()
true
}
else -> super.onOptionsItemSelected(item)
}
}

override fun itemTouchStartDrag(viewHolder: RecyclerView.ViewHolder) {
// Add visual highlight to the dragged item
(viewHolder.itemView as DraggableFrameLayout).isDragged = true
}

override fun itemTouchStopDrag(viewHolder: RecyclerView.ViewHolder) {
// Remove visual highlight from the dropped item
(viewHolder.itemView as DraggableFrameLayout).isDragged = false
}

override fun itemTouchOnMove(oldPosition: Int, newPosition: Int): Boolean {
// Determine the "drop area"
val firstDropPosition = itemAdapter.adapterItems.indexOfFirst { it is DraggableSingleLineItem }
val lastDropPosition = itemAdapter.adapterItems.indexOfLast { it is DraggableSingleLineItem }

// Only move the item if the new position is inside the "drop area"
return if (newPosition in firstDropPosition..lastDropPosition) {
// Change the item's position in the adapter
DragDropUtil.onMove(itemAdapter, oldPosition, newPosition)
true
} else {
false
}
}

override fun itemTouchDropped(oldPosition: Int, newPosition: Int) {
// Save the new item order, e.g. in your database
}
}
Expand Up @@ -88,6 +88,7 @@ class SampleActivity : AppCompatActivity() {
PrimaryDrawerItem().withName(R.string.sample_collapsible_multi_select_delete).withDescription(R.string.sample_collapsible_multi_select_delete_descr).withSelectable(false).withIdentifier(18).withIcon(MaterialDesignIconic.Icon.gmi_check_all),
PrimaryDrawerItem().withName(R.string.sample_sticky_header_mopub).withDescription(R.string.sample_sticky_header_mopub_descr).withSelectable(false).withIdentifier(19).withIcon(MaterialDesignIconic.Icon.gmi_accounts_list),
PrimaryDrawerItem().withName(R.string.sample_diff_util).withDescription(R.string.sample_diff_util_descr).withSelectable(false).withIdentifier(20).withIcon(MaterialDesignIconic.Icon.gmi_refresh),
PrimaryDrawerItem().withName(R.string.sample_drag_and_drop).withDescription(R.string.sample_drag_and_drop_descr).withSelectable(false).withIdentifier(22).withIcon(MaterialDesignIconic.Icon.gmi_reorder),
DividerDrawerItem(),
PrimaryDrawerItem().withName(R.string.open_source).withSelectable(false).withIdentifier(100).withIcon(MaterialDesignIconic.Icon.gmi_github)
)
Expand All @@ -114,6 +115,7 @@ class SampleActivity : AppCompatActivity() {
19L -> Intent(this@SampleActivity, StickyHeaderMopubAdsActivity::class.java)
20L -> Intent(this@SampleActivity, DiffUtilActivity::class.java)
21L -> Intent(this@SampleActivity, PagedActivity::class.java)
22L -> Intent(this@SampleActivity, DragAndDropActivity::class.java)
100L -> LibsBuilder()
.withFields(R.string::class.java.fields)
.withActivityTitle(getString(R.string.open_source))
Expand Down
@@ -0,0 +1,69 @@
package com.mikepenz.fastadapter.app.items

import android.graphics.drawable.Drawable
import android.view.MotionEvent
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.mikepenz.fastadapter.FastAdapter
import com.mikepenz.fastadapter.app.R
import com.mikepenz.fastadapter.drag.IDraggable
import com.mikepenz.fastadapter.items.AbstractItem
import com.mikepenz.fastadapter.listeners.TouchEventHook
import com.mikepenz.fastadapter.ui.utils.ImageHolder
import com.mikepenz.fastadapter.ui.utils.StringHolder

class DraggableSingleLineItem(icon: Drawable, name: String) : AbstractItem<DraggableSingleLineItem.ViewHolder>(), IDraggable {
val icon: ImageHolder = ImageHolder(icon)
val name: StringHolder = StringHolder(name)

override val isDraggable: Boolean = true

override val type: Int
get() = R.id.fastadapter_draggable_single_line_item

override val layoutRes: Int
get() = R.layout.draggable_single_line_item

override fun bindView(holder: ViewHolder, payloads: List<Any>) {
super.bindView(holder, payloads)
ImageHolder.applyToOrSetGone(icon, holder.icon)
name.applyTo(holder.name)
}

override fun unbindView(holder: ViewHolder) {
holder.icon.setImageDrawable(null)
holder.name.text = null
}

override fun getViewHolder(v: View): ViewHolder = ViewHolder(v)

class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
var icon: ImageView = view.findViewById(R.id.icon)
var name: TextView = view.findViewById(R.id.name)
var dragHandle: View = view.findViewById(R.id.drag_handle)
}
}

class DragHandleTouchEvent(val action: (position: Int) -> Unit) : TouchEventHook<DraggableSingleLineItem>() {
override fun onBind(viewHolder: RecyclerView.ViewHolder): View? {
return if (viewHolder is DraggableSingleLineItem.ViewHolder) viewHolder.dragHandle else null
}

override fun onTouch(
v: View,
event: MotionEvent,
position: Int,
fastAdapter: FastAdapter<DraggableSingleLineItem>,
item: DraggableSingleLineItem
): Boolean {
return if (event.action == MotionEvent.ACTION_DOWN) {
action(position)
true
} else {
false
}
}
}

0 comments on commit 72631f2

Please sign in to comment.