Skip to content

Commit

Permalink
Updated the recycler view library. Added a simple realization of 'rec…
Browse files Browse the repository at this point in the history
…yclerview-selection' library.| #793
  • Loading branch information
DenBond7 committed Jan 5, 2020
1 parent db6efdc commit f706fcd
Show file tree
Hide file tree
Showing 9 changed files with 160 additions and 9 deletions.
3 changes: 2 additions & 1 deletion FlowCrypt/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,8 @@ dependencies {
implementation "androidx.legacy:legacy-preference-v14:${rootProject.ext.androidxBaseVersion}"
implementation "androidx.cardview:cardview:${rootProject.ext.androidxBaseVersion}"
implementation "androidx.browser:browser:${rootProject.ext.androidxBaseVersion}"
implementation "androidx.recyclerview:recyclerview:${rootProject.ext.androidxBaseVersion}"
implementation "androidx.recyclerview:recyclerview:${rootProject.ext.recyclerViewVersion}"
implementation "androidx.recyclerview:recyclerview-selection:${rootProject.ext.recyclerViewVersion}-beta01"
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation "androidx.test.espresso:espresso-idling-resource:${rootProject.ext.espressoVersion}"
implementation "androidx.lifecycle:lifecycle-extensions:${rootProject.ext.lifecycleVersion}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,7 @@ class EmailManagerActivity : BaseEmailListActivity(), NavigationView.OnNavigatio
val fragment = supportFragmentManager
.findFragmentById(R.id.emailListFragment) as EmailListFragment?

//fragment?.onDrawerStateChanged(isOpen)
fragment?.onDrawerStateChanged(isOpen)
}

private fun initViews() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,21 @@ import android.content.Context
import android.os.Bundle
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.ProgressBar
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.ActionMode
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.paging.PagedList
import androidx.recyclerview.selection.SelectionTracker
import androidx.recyclerview.selection.StableIdKeyProvider
import androidx.recyclerview.selection.StorageStrategy
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
Expand All @@ -34,6 +41,7 @@ import com.flowcrypt.email.ui.activity.fragment.base.BaseSyncFragment
import com.flowcrypt.email.ui.activity.fragment.dialog.InfoDialogFragment
import com.flowcrypt.email.ui.activity.fragment.dialog.TwoWayDialogFragment
import com.flowcrypt.email.ui.adapter.MsgsPagedListAdapter
import com.flowcrypt.email.ui.adapter.selection.MsgItemDetailsLookup
import com.flowcrypt.email.util.GeneralUtil
import com.flowcrypt.email.util.UIUtil
import com.flowcrypt.email.util.idling.SingleIdlingResources
Expand All @@ -60,6 +68,8 @@ class EmailListFragment : BaseSyncFragment(), SwipeRefreshLayout.OnRefreshListen
private var swipeRefreshLayout: SwipeRefreshLayout? = null
private var textViewActionProgress: TextView? = null
private var progressBarActionProgress: ProgressBar? = null
private var tracker: SelectionTracker<Long>? = null
private var actionMode: ActionMode? = null

private lateinit var adapter: MsgsPagedListAdapter
private lateinit var messagesViewModel: MessagesViewModel
Expand Down Expand Up @@ -107,6 +117,26 @@ class EmailListFragment : BaseSyncFragment(), SwipeRefreshLayout.OnRefreshListen
}
}

private val selectionObserver = object : SelectionTracker.SelectionObserver<Long>() {
override fun onSelectionChanged() {
super.onSelectionChanged()
when {
tracker?.hasSelection() == true -> {
if (actionMode == null) {
actionMode = (this@EmailListFragment.activity as AppCompatActivity)
.startSupportActionMode(genActionModeForMsgs())
}
actionMode?.title = "${tracker?.selection?.size()}"
}

tracker?.hasSelection() == false -> {
actionMode?.finish()
actionMode = null
}
}
}
}

override val contentView: View?
get() = recyclerViewMsgs

Expand Down Expand Up @@ -290,6 +320,10 @@ class EmailListFragment : BaseSyncFragment(), SwipeRefreshLayout.OnRefreshListen
}

override fun onMsgClick(msgEntity: MessageEntity) {
if (tracker?.hasSelection() == true) {
return
}

val isOutbox = JavaEmailConstants.FOLDER_OUTBOX.equals(listener?.currentFolder?.fullName, ignoreCase = true)
val isRawMsgAvailable = msgEntity.rawMessageWithoutAttachments?.isNotEmpty()
if (isOutbox || isRawMsgAvailable == true || GeneralUtil.isConnected(context)) {
Expand All @@ -315,6 +349,15 @@ class EmailListFragment : BaseSyncFragment(), SwipeRefreshLayout.OnRefreshListen
onFolderChanged(deleteAllMsgs = true)
}

fun onDrawerStateChanged(isOpen: Boolean) {
//todo-denbond7 #793 need to fix that
/*if (isOpen) {
actionMode?.finish()
} else {
actionMode?.invalidate()
}*/
}

/**
* Reload the folder messages.
*/
Expand Down Expand Up @@ -439,10 +482,7 @@ class EmailListFragment : BaseSyncFragment(), SwipeRefreshLayout.OnRefreshListen
progressBarActionProgress = view.findViewById(R.id.progressBarActionProgress)

recyclerViewMsgs = view.findViewById(R.id.recyclerViewMsgs)
val layoutManager = LinearLayoutManager(context)
recyclerViewMsgs?.layoutManager = layoutManager
recyclerViewMsgs?.addItemDecoration(DividerItemDecoration(context, layoutManager.orientation))
recyclerViewMsgs?.adapter = adapter
setupRecyclerView()

footerProgressView = LayoutInflater.from(context).inflate(R.layout.list_view_progress_footer, recyclerViewMsgs, false)
footerProgressView?.visibility = View.GONE
Expand All @@ -453,6 +493,49 @@ class EmailListFragment : BaseSyncFragment(), SwipeRefreshLayout.OnRefreshListen
swipeRefreshLayout!!.setOnRefreshListener(this)
}

private fun setupRecyclerView() {
val layoutManager = LinearLayoutManager(context)
recyclerViewMsgs?.layoutManager = layoutManager
recyclerViewMsgs?.addItemDecoration(DividerItemDecoration(context, layoutManager.orientation))
recyclerViewMsgs?.adapter = adapter

adapter.tracker = null
recyclerViewMsgs?.let {
tracker = SelectionTracker.Builder(
EmailListFragment::class.java.simpleName,
it,
StableIdKeyProvider(it),
MsgItemDetailsLookup(it),
StorageStrategy.createLongStorage()
).build()
tracker?.addObserver(selectionObserver)
adapter.tracker = tracker
}
}

private fun genActionModeForMsgs(): ActionMode.Callback {
return object : ActionMode.Callback {
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
when (item?.itemId) {
else -> return false
}
}

override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
mode?.menuInflater?.inflate(R.menu.message_list_context_menu, menu)
swipeRefreshLayout?.isEnabled = false
return true
}

override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean = true

override fun onDestroyActionMode(mode: ActionMode?) {
swipeRefreshLayout?.isEnabled = true
tracker?.clearSelection()
}
}
}

interface OnManageEmailsListener {

val currentAccountDao: AccountDao?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import android.widget.TextView
import androidx.annotation.IntDef
import androidx.core.content.ContextCompat
import androidx.paging.PagedListAdapter
import androidx.recyclerview.selection.ItemDetailsLookup
import androidx.recyclerview.selection.SelectionTracker
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.flowcrypt.email.R
Expand All @@ -46,9 +48,11 @@ class MsgsPagedListAdapter(private val onMessageClickListener: OnMessageClickLis
PagedListAdapter<MessageEntity, MsgsPagedListAdapter.BaseViewHolder>(DIFF_CALLBACK) {
private val senderNamePattern: Pattern
private var isFooterEnabled = false
var tracker: SelectionTracker<Long>? = null

init {
this.senderNamePattern = prepareSenderNamePattern()
setHasStableIds(true)
}

override fun onCreateViewHolder(parent: ViewGroup, @ItemType viewType: Int): BaseViewHolder {
Expand All @@ -68,6 +72,8 @@ class MsgsPagedListAdapter(private val onMessageClickListener: OnMessageClickLis
}

override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
holder.setActivatedState(tracker?.isSelected(getItem(position)?.id) ?: false)

when (holder.itemType) {
MESSAGE -> {
val msgEntity = getItem(position)
Expand Down Expand Up @@ -98,6 +104,10 @@ class MsgsPagedListAdapter(private val onMessageClickListener: OnMessageClickLis
return currentItemCount + if (isFooterEnabled && currentItemCount > 0) 1 else 0
}

override fun getItemId(position: Int): Long {
return getItem(position)?.id ?: super.getItemId(position)
}

private fun updateItem(messageEntity: MessageEntity?, viewHolder: MessageViewHolder) {
val context = viewHolder.itemView.context
if (messageEntity != null) {
Expand Down Expand Up @@ -352,6 +362,15 @@ class MsgsPagedListAdapter(private val onMessageClickListener: OnMessageClickLis
abstract inner class BaseViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
@ItemType
abstract val itemType: Int

fun getItemDetails(): ItemDetailsLookup.ItemDetails<Long> = object : ItemDetailsLookup.ItemDetails<Long>() {
override fun getPosition(): Int = adapterPosition
override fun getSelectionKey(): Long? = itemId
}

fun setActivatedState(isActivated: Boolean) {
itemView.isActivated = isActivated
}
}

inner class MessageViewHolder(itemView: View) : BaseViewHolder(itemView) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* © 2016-2020 FlowCrypt Limited. Limitations apply. Contact [email protected]
* Contributors: DenBond7
*/

package com.flowcrypt.email.ui.adapter.selection

import android.view.MotionEvent
import androidx.recyclerview.selection.ItemDetailsLookup
import androidx.recyclerview.widget.RecyclerView
import com.flowcrypt.email.ui.adapter.MsgsPagedListAdapter

/**
* @author Denis Bondarenko
* Date: 1/5/20
* Time: 2:48 PM
* E-mail: [email protected]
*/
class MsgItemDetailsLookup(private val recyclerView: RecyclerView) : ItemDetailsLookup<Long>() {
override fun getItemDetails(e: MotionEvent): ItemDetails<Long>? {
return recyclerView.findChildViewUnder(e.x, e.y)?.let {
(recyclerView.getChildViewHolder(it) as? MsgsPagedListAdapter.BaseViewHolder)?.getItemDetails()
}
}
}
8 changes: 8 additions & 0 deletions FlowCrypt/src/main/res/drawable/selector_msg_item.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ © 2016-2019 FlowCrypt Limited. Limitations apply. Contact [email protected]
~ Contributors: DenBond7
-->

<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/silver" android:state_activated="true" />
</selector>
3 changes: 2 additions & 1 deletion FlowCrypt/src/main/res/layout/messages_list_item.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="@dimen/layout_height_message_item"
android:background="?attr/selectableItemBackground"
android:background="@drawable/selector_msg_item"
android:foreground="?attr/selectableItemBackground"
android:orientation="vertical">

<TextView
Expand Down
16 changes: 14 additions & 2 deletions FlowCrypt/src/main/res/menu/message_list_context_menu.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,21 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">

<item
android:id="@+id/menuActionArchiveMessage"
android:icon="@drawable/selector_ic_archive_white"
android:title="@string/archive"
app:showAsAction="always" />

<item
android:id="@+id/menuActionDeleteMessage"
android:icon="@drawable/ic_delete_white_24dp"
android:icon="@drawable/selector_ic_delete_white"
android:title="@string/delete"
app:showAsAction="ifRoom" />
app:showAsAction="always" />

<item
android:id="@+id/menuActionMarkUnread"
android:icon="@drawable/selector_ic_markunread_white"
android:title="@string/mark_unread"
app:showAsAction="always" />
</menu>
2 changes: 2 additions & 0 deletions ext.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ ext {
javaSourceCompatibility = '1.7'
/*https://developer.android.com/jetpack/androidx/androidx-rn*/
androidxBaseVersion = '1.0.0'
/* https://developer.android.com/jetpack/androidx/releases/recyclerview*/
recyclerViewVersion = '1.1.0'
/* https://developer.android.com/jetpack/androidx/releases/lifecycle*/
lifecycleVersion = '2.2.0-rc01'
/* https://developer.android.com/jetpack/androidx/releases/room#declaring_dependencies*/
Expand Down

0 comments on commit f706fcd

Please sign in to comment.