create an abstract MyAdapter that can be reused at multiple recycler adapters

This commit is contained in:
tibbi 2017-11-13 16:09:05 +01:00
parent c3a770ab43
commit 30b1cb40c6
5 changed files with 174 additions and 140 deletions

View File

@ -566,7 +566,7 @@ class MainActivity : SimpleActivity(), NavigationListener {
}
private fun launchAbout() {
startAboutActivity(R.string.app_name, LICENSE_KOTLIN or LICENSE_JODA or LICENSE_STETHO, BuildConfig.VERSION_NAME)
startAboutActivity(R.string.app_name, LICENSE_KOTLIN or LICENSE_JODA or LICENSE_STETHO or LICENSE_MULTISELECT, BuildConfig.VERSION_NAME)
}
private fun resetTitle() {

View File

@ -1,107 +1,42 @@
package com.simplemobiletools.calendar.adapters
import android.graphics.PorterDuff
import android.support.v7.view.ActionMode
import android.support.v7.widget.RecyclerView
import android.util.SparseArray
import android.view.*
import com.bignerdranch.android.multiselector.ModalMultiSelectorCallback
import com.bignerdranch.android.multiselector.MultiSelector
import com.bignerdranch.android.multiselector.SwappingHolder
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.SimpleActivity
import com.simplemobiletools.calendar.dialogs.DeleteEventDialog
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.extensions.shareEvents
import com.simplemobiletools.calendar.helpers.Formatter
import com.simplemobiletools.calendar.interfaces.DeleteEventsListener
import com.simplemobiletools.calendar.models.Event
import com.simplemobiletools.commons.extensions.beInvisible
import com.simplemobiletools.commons.extensions.beInvisibleIf
import com.simplemobiletools.commons.interfaces.MyAdapterListener
import kotlinx.android.synthetic.main.event_item_day_view.view.*
import java.util.*
class DayEventsAdapter(val activity: SimpleActivity, val events: List<Event>, val listener: DeleteEventsListener?, val itemClick: (Event) -> Unit) :
RecyclerView.Adapter<DayEventsAdapter.ViewHolder>() {
private val config = activity.config
private var actMode: ActionMode? = null
private var textColor = config.textColor
private val multiSelector = MultiSelector()
private var itemViews = SparseArray<View>()
private val selectedPositions = HashSet<Int>()
class DayEventsAdapter(activity: SimpleActivity, val events: List<Event>, val listener: DeleteEventsListener?, itemClick: (Any) -> Unit) :
MyAdapter(activity, itemClick) {
private var allDayString = activity.resources.getString(R.string.all_day)
private var replaceDescriptionWithLocation = config.replaceDescription
fun toggleItemSelection(select: Boolean, pos: Int) {
if (select) {
if (itemViews[pos] != null) {
selectedPositions.add(pos)
}
} else {
selectedPositions.remove(pos)
}
override fun getActionMenuId() = R.menu.cab_day
override fun markItemSelection(select: Boolean, pos: Int) {
itemViews[pos].event_item_frame.isSelected = select
if (selectedPositions.isEmpty()) {
finishActMode()
return
}
updateTitle(selectedPositions.size)
}
private fun updateTitle(cnt: Int) {
actMode?.title = "$cnt / ${events.size}"
actMode?.invalidate()
}
private val adapterListener = object : MyAdapterListener {
override fun toggleItemSelectionAdapter(select: Boolean, position: Int) {
toggleItemSelection(select, position)
override fun actionItemPressed(id: Int) {
when (id) {
R.id.cab_share -> shareEvents()
R.id.cab_delete -> askConfirmDelete()
}
override fun getSelectedPositions() = selectedPositions
}
private val multiSelectorMode = object : ModalMultiSelectorCallback(multiSelector) {
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
when (item.itemId) {
R.id.cab_share -> shareEvents()
R.id.cab_delete -> askConfirmDelete()
else -> return false
}
return true
}
override fun onCreateActionMode(actionMode: ActionMode?, menu: Menu?): Boolean {
super.onCreateActionMode(actionMode, menu)
actMode = actionMode
activity.menuInflater.inflate(R.menu.cab_day, menu)
return true
}
override fun onPrepareActionMode(actionMode: ActionMode?, menu: Menu) = true
override fun onDestroyActionMode(actionMode: ActionMode?) {
super.onDestroyActionMode(actionMode)
selectedPositions.forEach {
itemViews[it].event_item_frame.isSelected = false
}
selectedPositions.clear()
actMode = null
}
}
fun finishActMode() {
actMode?.finish()
}
private fun shareEvents() {
val selections = multiSelector.selectedPositions
val eventIds = ArrayList<Int>(selections.size)
selections.forEach {
val eventIds = ArrayList<Int>(selectedPositions.size)
selectedPositions.forEach {
eventIds.add(events[it].id)
}
activity.shareEvents(eventIds.distinct())
@ -109,10 +44,9 @@ class DayEventsAdapter(val activity: SimpleActivity, val events: List<Event>, va
}
private fun askConfirmDelete() {
val selections = multiSelector.selectedPositions
val eventIds = ArrayList<Int>(selections.size)
val timestamps = ArrayList<Int>(selections.size)
selections.forEach {
val eventIds = ArrayList<Int>(selectedPositions.size)
val timestamps = ArrayList<Int>(selectedPositions.size)
selectedPositions.forEach {
eventIds.add(events[it].id)
timestamps.add(events[it].startTS)
}
@ -129,71 +63,50 @@ class DayEventsAdapter(val activity: SimpleActivity, val events: List<Event>, va
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent?.context).inflate(R.layout.event_item_day_view, parent, false)
return ViewHolder(view, adapterListener, activity, multiSelectorMode, multiSelector, itemClick)
return createViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
override fun onBindViewHolder(holder: MyAdapter.ViewHolder, position: Int) {
val event = events[position]
itemViews.put(position, holder.bindView(event, textColor, replaceDescriptionWithLocation, allDayString))
val view = holder.bindView(event) {
setupView(it, event)
}
itemViews.put(position, view)
toggleItemSelection(selectedPositions.contains(position), position)
}
override fun getItemCount() = events.size
class ViewHolder(view: View, val adapterListener: MyAdapterListener, val activity: SimpleActivity, val multiSelectorCallback: ModalMultiSelectorCallback,
val multiSelector: MultiSelector, val itemClick: (Event) -> (Unit)) : SwappingHolder(view, MultiSelector()) {
fun bindView(event: Event, textColor: Int, replaceDescriptionWithLocation: Boolean, allDayString: String): View {
itemView.apply {
event_item_title.text = event.title
event_item_description.text = if (replaceDescriptionWithLocation) event.location else event.description
event_item_start.text = if (event.getIsAllDay()) allDayString else Formatter.getTimeFromTS(context, event.startTS)
event_item_end.beInvisibleIf(event.startTS == event.endTS)
event_item_color.setColorFilter(event.color, PorterDuff.Mode.SRC_IN)
private fun setupView(view: View, event: Event) {
view.apply {
event_item_title.text = event.title
event_item_description.text = if (replaceDescriptionWithLocation) event.location else event.description
event_item_start.text = if (event.getIsAllDay()) allDayString else Formatter.getTimeFromTS(context, event.startTS)
event_item_end.beInvisibleIf(event.startTS == event.endTS)
event_item_color.setColorFilter(event.color, PorterDuff.Mode.SRC_IN)
if (event.startTS != event.endTS) {
val startCode = Formatter.getDayCodeFromTS(event.startTS)
val endCode = Formatter.getDayCodeFromTS(event.endTS)
if (event.startTS != event.endTS) {
val startCode = Formatter.getDayCodeFromTS(event.startTS)
val endCode = Formatter.getDayCodeFromTS(event.endTS)
event_item_end.apply {
text = Formatter.getTimeFromTS(context, event.endTS)
if (startCode != endCode) {
if (event.getIsAllDay()) {
text = Formatter.getDateFromCode(context, endCode, true)
} else {
append(" (${Formatter.getDateFromCode(context, endCode, true)})")
}
} else if (event.getIsAllDay()) {
beInvisible()
event_item_end.apply {
text = Formatter.getTimeFromTS(context, event.endTS)
if (startCode != endCode) {
if (event.getIsAllDay()) {
text = Formatter.getDateFromCode(context, endCode, true)
} else {
append(" (${Formatter.getDateFromCode(context, endCode, true)})")
}
} else if (event.getIsAllDay()) {
beInvisible()
}
}
event_item_start.setTextColor(textColor)
event_item_end.setTextColor(textColor)
event_item_title.setTextColor(textColor)
event_item_description.setTextColor(textColor)
setOnClickListener { viewClicked(event) }
setOnLongClickListener { viewLongClicked(); true }
}
return itemView
}
private fun viewClicked(event: Event) {
if (multiSelector.isSelectable) {
val isSelected = adapterListener.getSelectedPositions().contains(adapterPosition)
adapterListener.toggleItemSelectionAdapter(!isSelected, adapterPosition)
} else {
itemClick(event)
}
}
private fun viewLongClicked() {
if (!multiSelector.isSelectable) {
activity.startSupportActionMode(multiSelectorCallback)
adapterListener.toggleItemSelectionAdapter(true, adapterPosition)
}
event_item_start.setTextColor(textColor)
event_item_end.setTextColor(textColor)
event_item_title.setTextColor(textColor)
event_item_description.setTextColor(textColor)
}
}
}

View File

@ -36,7 +36,7 @@ class EventListAdapter(val activity: SimpleActivity, val mItems: List<ListItem>,
val markedItems = HashSet<Int>()
var topDivider: Drawable? = null
var mNow = (System.currentTimeMillis() / 1000).toInt()
var now = (System.currentTimeMillis() / 1000).toInt()
var primaryColor = 0
var textColor = 0
var redTextColor = 0
@ -65,7 +65,7 @@ class EventListAdapter(val activity: SimpleActivity, val mItems: List<ListItem>,
textColor = activity.config.textColor
primaryColor = activity.config.primaryColor
val mTodayCode = Formatter.getDayCodeFromTS(mNow)
val mTodayCode = Formatter.getDayCodeFromTS(now)
todayDate = Formatter.getDayTitle(activity, mTodayCode)
replaceDescriptionWithLocation = activity.config.replaceDescription
}
@ -181,15 +181,15 @@ class EventListAdapter(val activity: SimpleActivity, val mItems: List<ListItem>,
var startTextColor = textColor
var endTextColor = textColor
if (item.startTS <= mNow && item.endTS <= mNow) {
if (item.startTS <= now && item.endTS <= now) {
if (item.isAllDay) {
if (Formatter.getDayCodeFromTS(item.startTS) == Formatter.getDayCodeFromTS(mNow))
if (Formatter.getDayCodeFromTS(item.startTS) == Formatter.getDayCodeFromTS(now))
startTextColor = primaryColor
} else {
startTextColor = redTextColor
}
endTextColor = redTextColor
} else if (item.startTS <= mNow && item.endTS >= mNow) {
} else if (item.startTS <= now && item.endTS >= now) {
startTextColor = primaryColor
}

View File

@ -0,0 +1,121 @@
package com.simplemobiletools.calendar.adapters
import android.support.v7.view.ActionMode
import android.support.v7.widget.RecyclerView
import android.util.SparseArray
import android.view.Menu
import android.view.MenuItem
import android.view.View
import com.bignerdranch.android.multiselector.ModalMultiSelectorCallback
import com.bignerdranch.android.multiselector.MultiSelector
import com.bignerdranch.android.multiselector.SwappingHolder
import com.simplemobiletools.calendar.activities.SimpleActivity
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.commons.interfaces.MyAdapterListener
import java.util.*
abstract class MyAdapter(val activity: SimpleActivity, val itemClick: (Any) -> Unit) : RecyclerView.Adapter<MyAdapter.ViewHolder>() {
protected val config = activity.config
protected var actMode: ActionMode? = null
protected var primaryColor = config.primaryColor
protected var textColor = config.textColor
protected var itemViews = SparseArray<View>()
protected val selectedPositions = HashSet<Int>()
protected val multiSelector = MultiSelector()
abstract fun getActionMenuId(): Int
abstract fun markItemSelection(select: Boolean, pos: Int)
abstract fun actionItemPressed(id: Int)
protected fun toggleItemSelection(select: Boolean, pos: Int) {
if (select) {
if (itemViews[pos] != null) {
selectedPositions.add(pos)
}
} else {
selectedPositions.remove(pos)
}
markItemSelection(select, pos)
if (selectedPositions.isEmpty()) {
finishActMode()
return
}
updateTitle(selectedPositions.size)
}
private fun updateTitle(cnt: Int) {
actMode?.title = "$cnt / $itemCount"
actMode?.invalidate()
}
private val adapterListener = object : MyAdapterListener {
override fun toggleItemSelectionAdapter(select: Boolean, position: Int) {
toggleItemSelection(select, position)
}
override fun getSelectedPositions() = selectedPositions
}
private val multiSelectorMode = object : ModalMultiSelectorCallback(multiSelector) {
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
actionItemPressed(item.itemId)
return true
}
override fun onCreateActionMode(actionMode: ActionMode?, menu: Menu?): Boolean {
super.onCreateActionMode(actionMode, menu)
actMode = actionMode
activity.menuInflater.inflate(getActionMenuId(), menu)
return true
}
override fun onPrepareActionMode(actionMode: ActionMode?, menu: Menu) = true
override fun onDestroyActionMode(actionMode: ActionMode?) {
super.onDestroyActionMode(actionMode)
selectedPositions.forEach {
markItemSelection(false, it)
}
selectedPositions.clear()
actMode = null
}
}
fun finishActMode() {
actMode?.finish()
}
protected fun createViewHolder(view: View) = ViewHolder(view, adapterListener, activity, multiSelectorMode, multiSelector, itemClick)
class ViewHolder(view: View, val adapterListener: MyAdapterListener, val activity: SimpleActivity, val multiSelectorCallback: ModalMultiSelectorCallback,
val multiSelector: MultiSelector, val itemClick: (Any) -> (Unit)) : SwappingHolder(view, multiSelector) {
fun bindView(any: Any, callback: (itemView: View) -> Unit): View {
return itemView.apply {
callback(this)
itemView.setOnClickListener { viewClicked(any) }
itemView.setOnLongClickListener { viewLongClicked(); true }
}
}
private fun viewClicked(any: Any) {
if (multiSelector.isSelectable) {
val isSelected = adapterListener.getSelectedPositions().contains(adapterPosition)
adapterListener.toggleItemSelectionAdapter(!isSelected, adapterPosition)
} else {
itemClick(any)
}
}
private fun viewLongClicked() {
if (!multiSelector.isSelectable) {
activity.startSupportActionMode(multiSelectorCallback)
adapterListener.toggleItemSelectionAdapter(true, adapterPosition)
}
}
}
}

View File

@ -140,7 +140,7 @@ class DayFragment : Fragment(), DBHelper.EventUpdateListener, DeleteEventsListen
return
val eventsAdapter = DayEventsAdapter(activity as SimpleActivity, events, this) {
editEvent(it)
editEvent(it as Event)
}
mHolder.day_events.adapter = eventsAdapter