Drag and drop to rearrange drawer

pull/1020/head
Alex Baker 4 years ago
parent e297ed4bd2
commit 745c17fbc5

@ -284,6 +284,8 @@
android:taskAffinity=""
android:theme="@style/TranslucentDialog"/>
<activity android:name=".activities.NavigationDrawerCustomization" />
<activity android:name=".activities.TagSettingsActivity"/>
<activity android:name=".activities.FilterSettingsActivity"/>

@ -38,6 +38,8 @@ class FilterViewHolder internal constructor(
@BindView(R.id.size)
lateinit var size: TextView
lateinit var filter: FilterListItem
init {
ButterKnife.bind(this, itemView)
if (navigationDrawer) {
@ -45,7 +47,12 @@ class FilterViewHolder internal constructor(
}
}
fun setMoving(moving: Boolean) {
itemView.isSelected = moving
}
fun bind(filter: FilterListItem, selected: Boolean, count: Int?) {
this.filter = filter
if (navigationDrawer) {
itemView.isSelected = selected
} else {

@ -9,12 +9,14 @@ import android.app.Activity
import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.AsyncListDiffer
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.todoroo.astrid.api.Filter
import com.todoroo.astrid.api.FilterListItem
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.subjects.PublishSubject
import org.tasks.LocalBroadcastManager
import org.tasks.activities.DragAndDropDiffer
import org.tasks.billing.Inventory
import org.tasks.data.CaldavDao
import org.tasks.data.GoogleTaskDao
@ -22,6 +24,7 @@ import org.tasks.filters.NavigationDrawerSubheader
import org.tasks.locale.Locale
import org.tasks.preferences.Preferences
import org.tasks.themes.ColorProvider
import java.util.*
import javax.inject.Inject
import kotlin.math.max
@ -34,11 +37,15 @@ class NavigationDrawerAdapter @Inject constructor(
private val googleTaskDao: GoogleTaskDao,
private val caldavDao: CaldavDao,
private val localBroadcastManager: LocalBroadcastManager)
: RecyclerView.Adapter<RecyclerView.ViewHolder>() {
: RecyclerView.Adapter<RecyclerView.ViewHolder>(), DragAndDropDiffer<FilterListItem, MutableList<FilterListItem>> {
private lateinit var onClick: (FilterListItem?) -> Unit
private var selected: Filter? = null
private val differ = AsyncListDiffer(this, DiffCallback())
override val disposables = CompositeDisposable()
override val publishSubject = PublishSubject.create<MutableList<FilterListItem>>()
override val updates: Queue<Pair<MutableList<FilterListItem>, DiffUtil.DiffResult?>> = LinkedList()
override var items = initializeDiffer(ArrayList())
override var dragging = false
fun setOnClick(onClick: (FilterListItem?) -> Unit) {
this.onClick = onClick
@ -54,7 +61,7 @@ class NavigationDrawerAdapter @Inject constructor(
override fun getItemId(position: Int) = position.toLong()
override fun getItemCount() = differ.currentList.size
override fun getItemCount() = items.size
fun setSelected(selected: Filter?) {
this.selected = selected
@ -90,17 +97,38 @@ class NavigationDrawerAdapter @Inject constructor(
override fun getItemViewType(position: Int) = getItem(position).itemType.ordinal
private fun getItem(position: Int) = differ.currentList[position]
private fun getItem(position: Int) = items[position]
fun submitList(filterListItems: List<FilterListItem>) = differ.submitList(filterListItems)
override fun transform(list: List<FilterListItem>) = list.toMutableList()
private class DiffCallback : DiffUtil.ItemCallback<FilterListItem>() {
override fun areItemsTheSame(old: FilterListItem, new: FilterListItem) = old.areItemsTheSame(new)
override fun diff(last: MutableList<FilterListItem>, next: MutableList<FilterListItem>) =
DiffUtil.calculateDiff(DiffCallback(last, next))
override fun areContentsTheSame(old: FilterListItem, new: FilterListItem) = old.areContentsTheSame(new)
private class DiffCallback(val old: List<FilterListItem>, val new: List<FilterListItem>) : DiffUtil.Callback() {
override fun getOldListSize() = old.size
override fun getNewListSize() = new.size
override fun areItemsTheSame(oldPosition: Int, newPosition: Int) =
old[oldPosition].areItemsTheSame(new[newPosition])
override fun areContentsTheSame(oldPosition: Int, newPosition: Int) =
old[oldPosition].areContentsTheSame(new[newPosition])
}
companion object {
private const val TOKEN_SELECTED = "token_selected"
}
override fun onChanged(position: Int, count: Int, payload: Any?) =
notifyItemRangeChanged(position, count, payload)
override fun onMoved(fromPosition: Int, toPosition: Int) =
notifyItemMoved(fromPosition, toPosition)
override fun onInserted(position: Int, count: Int) =
notifyItemRangeInserted(position, count)
override fun onRemoved(position: Int, count: Int) =
notifyItemRangeRemoved(position, count)
}

@ -74,6 +74,10 @@ public class CaldavFilter extends Filter {
return calendar.getUuid();
}
public String getAccount() {
return calendar.getAccount();
}
public CaldavCalendar getCalendar() {
return calendar;
}

@ -73,7 +73,8 @@ public abstract class FilterListItem implements Parcelable {
return Objects.equals(listingTitle, other.listingTitle)
&& icon == other.icon
&& tint == other.tint
&& count == other.count;
&& count == other.count
&& order == other.order;
}
@Override

@ -71,6 +71,10 @@ public class GtasksFilter extends Filter {
return list.getId();
}
public String getAccount() {
return list.getAccount();
}
public GoogleTaskList getList() {
return list;
}

@ -0,0 +1,66 @@
package org.tasks.activities
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListUpdateCallback
import com.todoroo.andlib.utility.AndroidUtilities
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import io.reactivex.subjects.PublishSubject
import java.util.*
interface DragAndDropDiffer<T, R> : ListUpdateCallback {
val publishSubject: PublishSubject<R>
val updates: Queue<Pair<R, DiffUtil.DiffResult?>>
val disposables: CompositeDisposable
var items: R
var dragging: Boolean
fun submitList(list: List<T>) {
disposables.add(
Single.fromCallable { transform(list) }
.subscribeOn(Schedulers.computation())
.subscribe(publishSubject::onNext))
}
fun calculateDiff(last: Pair<R, DiffUtil.DiffResult?>, next: R): Pair<R, DiffUtil.DiffResult?> {
AndroidUtilities.assertNotMainThread()
return Pair(next, diff(last.first!!, next))
}
fun applyDiff(update: Pair<R, DiffUtil.DiffResult?>) {
AndroidUtilities.assertMainThread()
updates.add(update)
if (!dragging) {
drainQueue()
}
}
fun drainQueue() {
AndroidUtilities.assertMainThread()
var update = updates.poll()
while (update != null) {
items = update.first
update.second?.dispatchUpdatesTo(this as ListUpdateCallback)
update = updates.poll()
}
}
fun initializeDiffer(list: List<T>): R {
val initial = transform(list)
disposables.add(publishSubject
.observeOn(Schedulers.computation())
.scan(Pair(initial, null), { last: Pair<R, DiffUtil.DiffResult?>, next: R ->
calculateDiff(last, next)
})
.skip(1)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::applyDiff))
return initial
}
fun transform(list: List<T>): R
fun diff(last: R, next: R): DiffUtil.DiffResult
}

@ -244,8 +244,11 @@ class FilterSettingsActivity : BaseListSettingsActivity() {
if (isNew) {
f.id = filterDao.insert(f)
} else {
f.id = filter!!.id
filterDao.update(f)
filter?.let {
f.id = it.id
f.order = it.order
filterDao.update(f)
}
}
setResult(
Activity.RESULT_OK,

@ -0,0 +1,266 @@
package org.tasks.activities
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.Parcelable
import android.view.MenuItem
import androidx.appcompat.widget.Toolbar
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.ItemTouchHelper.*
import androidx.recyclerview.widget.ItemTouchHelper.Callback.makeMovementFlags
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.todoroo.astrid.adapter.FilterViewHolder
import com.todoroo.astrid.adapter.NavigationDrawerAdapter
import com.todoroo.astrid.api.*
import com.todoroo.astrid.api.FilterListItem.Type.ITEM
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import org.tasks.LocalBroadcastManager
import org.tasks.R
import org.tasks.caldav.BaseCaldavCalendarSettingsActivity
import org.tasks.data.*
import org.tasks.databinding.ActivityTagOrganizerBinding
import org.tasks.dialogs.NewFilterDialog.Companion.newFilterDialog
import org.tasks.filters.FilterProvider
import org.tasks.filters.NavigationDrawerAction
import org.tasks.filters.PlaceFilter
import org.tasks.injection.ActivityComponent
import org.tasks.injection.ThemedInjectingAppCompatActivity
import org.tasks.preferences.Preferences
import org.tasks.ui.NavigationDrawerFragment.Companion.REQUEST_NEW_FILTER
import javax.inject.Inject
class NavigationDrawerCustomization : ThemedInjectingAppCompatActivity(), Toolbar.OnMenuItemClickListener {
@Inject lateinit var filterProvider: FilterProvider
@Inject lateinit var adapter: NavigationDrawerAdapter
@Inject lateinit var localBroadcastManager: LocalBroadcastManager
@Inject lateinit var preferences: Preferences
@Inject lateinit var tagDataDao: TagDataDao
@Inject lateinit var googleTaskListDao: GoogleTaskListDao
@Inject lateinit var filterDao: FilterDao
@Inject lateinit var caldavDao: CaldavDao
@Inject lateinit var locationDao: LocationDao
private lateinit var binding: ActivityTagOrganizerBinding
private lateinit var toolbar: Toolbar
private var disposables: CompositeDisposable? = null
private val refreshReceiver = RefreshReceiver()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityTagOrganizerBinding.inflate(layoutInflater)
setContentView(binding.root)
toolbar = binding.toolbar.toolbar
toolbar.title = getString(R.string.manage_lists)
toolbar.navigationIcon = getDrawable(R.drawable.ic_outline_arrow_back_24px)
toolbar.setNavigationOnClickListener { finish() }
toolbar.setOnMenuItemClickListener(this)
toolbar.inflateMenu(R.menu.menu_nav_drawer_customization)
themeColor.apply(toolbar)
themeColor.applyToSystemBars(this)
adapter.setOnClick(this::onClick)
binding.recyclerView.layoutManager = LinearLayoutManager(this)
binding.recyclerView.adapter = adapter
val itemTouchHelper = ItemTouchHelper(ItemTouchHelperCallback())
itemTouchHelper.attachToRecyclerView(binding.recyclerView)
}
override fun onPause() {
super.onPause()
localBroadcastManager.unregisterReceiver(refreshReceiver)
}
override fun onStart() {
super.onStart()
disposables = CompositeDisposable()
}
override fun onStop() {
super.onStop()
disposables?.dispose()
}
override fun onResume() {
super.onResume()
localBroadcastManager.registerRefreshListReceiver(refreshReceiver)
updateFilters()
}
private fun updateFilters() =
disposables?.add(
Single.fromCallable {
filterProvider.drawerCustomizationItems.apply {
forEach { f -> f.count = 0 }
}
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(adapter::submitList))
private fun onClick(item: FilterListItem?) {
if (item is NavigationDrawerAction) {
when (item.requestCode) {
REQUEST_NEW_FILTER ->
newFilterDialog().show(supportFragmentManager, FRAG_TAG_NEW_FILTER)
else -> startActivity(item.intent)
}
} else {
when (item) {
is GtasksFilter ->
Intent(this, GoogleTaskListSettingsActivity::class.java)
.putExtra(GoogleTaskListSettingsActivity.EXTRA_STORE_DATA, item.list)
.apply(this::startActivity)
is CaldavFilter ->
caldavDao.getAccountByUuid(item.account)?.let {
Intent(this, it.listSettingsClass())
.putExtra(BaseCaldavCalendarSettingsActivity.EXTRA_CALDAV_CALENDAR, item.calendar)
.apply(this::startActivity)
}
is CustomFilter ->
Intent(this, FilterSettingsActivity::class.java)
.putExtra(FilterSettingsActivity.TOKEN_FILTER, item)
.apply(this::startActivity)
is TagFilter ->
Intent(this, TagSettingsActivity::class.java)
.putExtra(TagSettingsActivity.EXTRA_TAG_DATA, item.tagData)
.apply(this::startActivity)
is PlaceFilter ->
Intent(this, PlaceSettingsActivity::class.java)
.putExtra(PlaceSettingsActivity.EXTRA_PLACE, item.place as Parcelable)
.apply(this::startActivity)
}
}
}
override fun inject(component: ActivityComponent) = component.inject(this)
override fun onMenuItemClick(item: MenuItem): Boolean {
return if (item.itemId == R.id.reset_sort) {
filterDao.resetOrders()
caldavDao.resetOrders()
googleTaskListDao.resetOrders()
tagDataDao.resetOrders()
locationDao.resetOrders()
updateFilters()
true
} else {
false
}
}
private inner class RefreshReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent?) {
val action = intent?.action
if (LocalBroadcastManager.REFRESH == action || LocalBroadcastManager.REFRESH_LIST == action) {
updateFilters()
}
}
}
private inner class ItemTouchHelperCallback : ItemTouchHelper.Callback() {
private var from = -1
private var to = -1
override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) =
if (viewHolder.itemViewType == ITEM.ordinal) ALLOW_DRAGGING else NO_MOVEMENT
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
super.onSelectedChanged(viewHolder, actionState)
if (actionState == ACTION_STATE_DRAG) {
adapter.dragging = true
(viewHolder as FilterViewHolder).setMoving(true)
}
}
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
if (target !is FilterViewHolder) {
return false
}
val sourceFilter = (viewHolder as FilterViewHolder).filter
val targetFilter = target.filter
if (sourceFilter::class.java != targetFilter::class.java) {
return false
}
if (sourceFilter is GtasksFilter && targetFilter is GtasksFilter) {
if (sourceFilter.account != targetFilter.account) {
return false
}
} else if (sourceFilter is CaldavFilter && targetFilter is CaldavFilter) {
if (sourceFilter.account != targetFilter.account) {
return false
}
}
val sourcePosition = viewHolder.adapterPosition
if (from == -1) {
from = sourcePosition
}
to = target.adapterPosition
adapter.notifyItemMoved(sourcePosition, to)
return true
}
override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
super.clearView(recyclerView, viewHolder)
(viewHolder as FilterViewHolder).setMoving(false)
if (from != to) {
viewHolder.filter.order = to
adapter.items
.apply {
removeAt(from)
add(to, viewHolder.filter)
}
.filter(getPredicate(viewHolder.filter))
.forEachIndexed { order, filter ->
filter.order = order
setOrder(order, filter)
}
updateFilters()
}
adapter.dragging = false
from = -1
to = -1
}
private fun getPredicate(item: FilterListItem): (FilterListItem) -> Boolean = { f ->
item::class.java == f::class.java && when (item) {
is GtasksFilter -> item.account == (f as GtasksFilter).account
is CaldavFilter -> item.account == (f as CaldavFilter).account
else -> true
}
}
private fun setOrder(order: Int, filter: FilterListItem) {
when (filter) {
is GtasksFilter -> googleTaskListDao.setOrder(filter.list.id, order)
is CaldavFilter -> caldavDao.setOrder(filter.calendar.id, order)
is TagFilter -> tagDataDao.setOrder(filter.tagData.id!!, order)
is CustomFilter -> filterDao.setOrder(filter.id, order)
is PlaceFilter -> locationDao.setOrder(filter.place.id, order)
}
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {}
}
companion object {
private val NO_MOVEMENT = makeMovementFlags(0, 0)
private val ALLOW_DRAGGING = makeMovementFlags(UP or DOWN, 0)
private const val FRAG_TAG_NEW_FILTER = "frag_tag_new_filter"
}
}

@ -11,6 +11,7 @@ import com.todoroo.astrid.core.BuiltInFilterExposer
import org.tasks.BuildConfig
import org.tasks.R
import org.tasks.activities.GoogleTaskListSettingsActivity
import org.tasks.activities.NavigationDrawerCustomization
import org.tasks.activities.TagSettingsActivity
import org.tasks.billing.Inventory
import org.tasks.caldav.BaseCaldavCalendarSettingsActivity
@ -45,6 +46,9 @@ class FilterProvider @Inject constructor(
val filterPickerItems: List<FilterListItem>
get() = getAllFilters(showCreate = false)
val drawerCustomizationItems: List<FilterListItem>
get() = getAllFilters(showBuiltIn = false)
private fun addFilters(showCreate: Boolean, showBuiltIn: Boolean): List<FilterListItem> =
if (!preferences.getBoolean(R.string.p_filters_enabled, true)) {
emptyList()
@ -154,6 +158,11 @@ class FilterProvider @Inject constructor(
R.drawable.ic_outline_attach_money_24px,
NavigationDrawerFragment.REQUEST_PURCHASE)
}
.plus(NavigationDrawerAction(
context.getString(R.string.manage_lists),
R.drawable.ic_outline_edit_24px,
Intent(context, NavigationDrawerCustomization::class.java),
0))
.plus(NavigationDrawerAction(
context.getString(R.string.TLA_menu_settings),
R.drawable.ic_outline_settings_24px,

@ -77,4 +77,5 @@ interface ActivityComponent {
fun inject(activity: SyncPreferences)
fun inject(activity: PlaceSettingsActivity)
fun inject(activity: LocalListSettingsActivity)
fun inject(activity: NavigationDrawerCustomization)
}

@ -2,23 +2,18 @@ package org.tasks.tasklist
import android.graphics.Canvas
import android.view.ViewGroup
import androidx.core.util.Pair
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.ItemTouchHelper.*
import androidx.recyclerview.widget.ItemTouchHelper.Callback.makeMovementFlags
import androidx.recyclerview.widget.ListUpdateCallback
import androidx.recyclerview.widget.RecyclerView
import com.todoroo.andlib.utility.AndroidUtilities
import com.todoroo.astrid.activity.TaskListFragment
import com.todoroo.astrid.adapter.TaskAdapter
import com.todoroo.astrid.dao.TaskDao
import com.todoroo.astrid.utility.Flags
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import io.reactivex.subjects.PublishSubject
import org.tasks.activities.DragAndDropDiffer
import org.tasks.data.TaskContainer
import org.tasks.preferences.Preferences
import java.util.*
@ -32,19 +27,26 @@ class DragAndDropRecyclerAdapter(
private val taskList: TaskListFragment,
tasks: List<TaskContainer>,
taskDao: TaskDao,
preferences: Preferences) : TaskListRecyclerAdapter(adapter, viewHolderFactory, taskList, taskDao, preferences) {
private var list: SectionedDataSource
private val publishSubject = PublishSubject.create<SectionedDataSource>()
private val disposables = CompositeDisposable()
private val updates: Queue<Pair<SectionedDataSource, DiffUtil.DiffResult>> = LinkedList()
private var dragging = false
private val disableHeaders: Boolean
private val itemTouchHelper: ItemTouchHelper
preferences: Preferences) : TaskListRecyclerAdapter(adapter, viewHolderFactory, taskList, taskDao, preferences), DragAndDropDiffer<TaskContainer, SectionedDataSource> {
private val disableHeaders = taskList.getFilter().let {
!it.supportsSorting()
|| !preferences.showGroupHeaders()
|| (it.supportsManualSort() && preferences.isManualSort)
|| (it.supportsAstridSorting() && preferences.isAstridSort)
}
private val itemTouchHelper = ItemTouchHelper(ItemTouchHelperCallback()).apply {
attachToRecyclerView(recyclerView)
}
override val publishSubject = PublishSubject.create<SectionedDataSource>()
override val disposables = CompositeDisposable()
override val updates: Queue<Pair<SectionedDataSource, DiffUtil.DiffResult?>> = LinkedList()
override var dragging = false
override var items = initializeDiffer(tasks)
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val viewType = getItemViewType(position)
if (viewType == 1) {
val headerSection = list.getSection(position)
val headerSection = items.getSection(position)
(holder as HeaderViewHolder).bind(taskList.getFilter(), preferences.sortMode, headerSection)
} else {
super.onBindViewHolder(holder, position)
@ -52,9 +54,11 @@ class DragAndDropRecyclerAdapter(
}
override val sortMode: Int
get() = list.sortMode
get() = items.sortMode
override fun getItemViewType(position: Int) = if (items.isHeader(position)) 1 else 0
override fun getItemViewType(position: Int) = if (list.isHeader(position)) 1 else 0
override fun submitList(list: List<TaskContainer>) = super.submitList(list)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder = if (viewType == 1) {
viewHolderFactory.newHeaderViewHolder(parent, this::toggleGroup)
@ -69,44 +73,21 @@ class DragAndDropRecyclerAdapter(
override fun dragAndDropEnabled() = taskList.getFilter().supportsSubtasks()
override fun isHeader(position: Int): Boolean = list.isHeader(position)
override fun isHeader(position: Int): Boolean = items.isHeader(position)
override fun nearestHeader(position: Int) = list.getNearestHeader(position)
override fun nearestHeader(position: Int) = items.getNearestHeader(position)
override fun getItem(position: Int) = list.getItem(position)
override fun getItem(position: Int) = items.getItem(position)
override fun submitList(list: List<TaskContainer>) {
disposables.add(
Single.fromCallable { SectionedDataSource(list, disableHeaders, preferences.sortMode, adapter.getCollapsed()) }
.subscribeOn(Schedulers.computation())
.subscribe(publishSubject::onNext))
}
private fun calculateDiff(
last: Pair<SectionedDataSource, DiffUtil.DiffResult>, next: SectionedDataSource): Pair<SectionedDataSource, DiffUtil.DiffResult> {
AndroidUtilities.assertNotMainThread()
val cb = DiffCallback(last.first!!, next, adapter)
val result = DiffUtil.calculateDiff(cb, next.size < LONG_LIST_SIZE)
return Pair.create(next, result)
}
override fun transform(list: List<TaskContainer>): SectionedDataSource =
SectionedDataSource(list, disableHeaders, preferences.sortMode, adapter.getCollapsed())
private fun applyDiff(update: Pair<SectionedDataSource, DiffUtil.DiffResult>) {
AndroidUtilities.assertMainThread()
updates.add(update)
if (!dragging) {
drainQueue()
}
}
override fun diff(last: SectionedDataSource, next: SectionedDataSource) =
DiffUtil.calculateDiff(DiffCallback(last, next, adapter), next.size < LONG_LIST_SIZE)
private fun drainQueue() {
AndroidUtilities.assertMainThread()
override fun drainQueue() {
val recyclerViewState = recyclerView.layoutManager!!.onSaveInstanceState()
var update = updates.poll()
while (update != null) {
list = update.first!!
update.second!!.dispatchUpdatesTo((this as ListUpdateCallback))
update = updates.poll()
}
super.drainQueue()
recyclerView.layoutManager!!.onRestoreInstanceState(recyclerViewState)
}
@ -115,9 +96,9 @@ class DragAndDropRecyclerAdapter(
disposables.dispose()
}
override fun getTaskCount() = list.taskCount
override fun getTaskCount() = items.taskCount
override fun getItemCount() = list.size
override fun getItemCount() = items.size
private inner class ItemTouchHelperCallback : ItemTouchHelper.Callback() {
private var from = -1
@ -162,7 +143,7 @@ class DragAndDropRecyclerAdapter(
notifyItemMoved(fromPosition, toPosition)
if (isHeader) {
val offset = if (fromPosition < toPosition) -1 else 1
list.moveSection(toPosition, offset)
items.moveSection(toPosition, offset)
}
updateIndents(source, from, to)
return true
@ -257,8 +238,8 @@ class DragAndDropRecyclerAdapter(
from
}
adapter.moved(from, to, indent)
val task: TaskContainer = list.removeAt(from)
list.add(if (from < to) to - 1 else to, task)
val task: TaskContainer = items.removeAt(from)
items.add(if (from < to) to - 1 else to, task)
taskList.loadTaskListContent()
}
}
@ -268,24 +249,4 @@ class DragAndDropRecyclerAdapter(
private val NO_MOVEMENT = makeMovementFlags(0, 0)
private val ALLOW_DRAGGING = makeMovementFlags(UP or DOWN or LEFT or RIGHT, 0)
}
init {
val filter = taskList.getFilter()
disableHeaders = !filter.supportsSorting()
|| !preferences.showGroupHeaders()
|| (filter.supportsManualSort() && preferences.isManualSort)
|| (filter.supportsAstridSorting() && preferences.isAstridSort)
itemTouchHelper = ItemTouchHelper(ItemTouchHelperCallback())
itemTouchHelper.attachToRecyclerView(recyclerView)
list = SectionedDataSource(tasks, disableHeaders, preferences.sortMode, adapter.getCollapsed().toMutableSet())
val initial = Pair.create<SectionedDataSource, DiffUtil.DiffResult>(list, null)
disposables.add(publishSubject
.observeOn(Schedulers.computation())
.scan(initial, { last: Pair<SectionedDataSource, DiffUtil.DiffResult>, next: SectionedDataSource ->
calculateDiff(last, next)
})
.skip(1)
.observeOn(AndroidSchedulers.mainThread())
.subscribe { update: Pair<SectionedDataSource, DiffUtil.DiffResult> -> applyDiff(update) })
}
}

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include
android:id="@+id/toolbar"
layout="@layout/toolbar" />
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/recycler_view" />
</LinearLayout>

@ -6,8 +6,7 @@
android:id="@+id/subheader_row"
android:background="?attr/selectableItemBackground"
android:focusable="true"
android:layout_height="wrap_content"
android:orientation="vertical">
android:layout_height="wrap_content">
<View
android:id="@+id/divider"
@ -45,15 +44,12 @@
android:fontFamily="@string/font_fontFamily_medium"
android:layout_alignParentStart="true"
android:layout_below="@id/divider"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:gravity="start|center_vertical"
android:drawableTint="@color/icon_tint_with_alpha"
android:singleLine="true"
android:textAlignment="viewStart"
android:textSize="14sp"
android:paddingStart="@dimen/keyline_first"
android:paddingEnd="@dimen/keyline_first"
android:padding="@dimen/keyline_first"
tools:ignore="UnusedAttribute" />
</RelativeLayout>

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/reset_sort"
android:title="@string/reset_sort_order"
app:showAsAction="never" />
</menu>

@ -30,6 +30,7 @@ File %1$s contained %2$s.\n\n
<string name="TLA_menu_search">Search</string>
<string name="TLA_menu_settings">Settings</string>
<string name="TAd_actionEditTask">Edit</string>
<string name="manage_lists">Manage lists</string>
<string name="action_call">Call</string>
<string name="action_open">Open</string>
<string name="SSD_sort_my_order">My order</string>
@ -634,4 +635,5 @@ File %1$s contained %2$s.\n\n
<string name="on_launch">On launch</string>
<string name="open_last_viewed_list">Open last viewed list</string>
<string name="lists">Lists</string>
<string name="reset_sort_order">Reset sort order</string>
</resources>

Loading…
Cancel
Save