Skip to content

Instantly share code, notes, and snippets.

@long1eu
Created August 23, 2017 18:48
Show Gist options
  • Save long1eu/db237146e93e0d8d0bf7cf327134c2df to your computer and use it in GitHub Desktop.
Save long1eu/db237146e93e0d8d0bf7cf327134c2df to your computer and use it in GitHub Desktop.
package eu.long1.jwnotes.models.flexible
import android.content.Context
import android.os.Parcel
import android.os.Parcelable
import android.view.View
import android.widget.TextView
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import eu.davidea.flexibleadapter.items.IHolder
import eu.davidea.viewholders.FlexibleViewHolder
import eu.long1.jwnotes.Log
import eu.long1.jwnotes.R
import eu.long1.jwnotes.custom.views.FlipView
import eu.long1.jwnotes.data.tables.ContactsTable
import eu.long1.jwnotes.models.firebase.Talk
import eu.long1.jwnotes.models.firebase.User
import java.util.*
class ITalk(private val talk: Talk) : AbstractFlexibleItem<ITalk.TalkItemVH>(), IHolder<Talk>, Parcelable {
var lastPosition: Int = 0
private set
init {
isSwipeable = true
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null) return false
if (javaClass != other.javaClass) return false
val iTalk = other as ITalk
return talk == iTalk.talk
}
override fun hashCode(): Int = talk.hashCode()
override fun getLayoutRes(): Int = R.layout.fragment_main_swipe_layout
override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): TalkItemVH = TalkItemVH(view, adapter)
override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: TalkItemVH, position: Int, payloads: List<*>?) {
val context = holder.contentView.context
holder.title.text = talk.title
holder.speaker.text = talk.speaker
if (User.getUserUid() == "own") {
if (holder.owner.visibility != View.INVISIBLE) {
holder.owner.visibility = View.INVISIBLE
}
} else {
if (holder.owner.visibility != View.VISIBLE) {
holder.owner.visibility = View.VISIBLE
}
holder.owner.text = ContactsTable.instance.getName(talk.ownerUid)
}
var dateAndLocation = getDate(Date(talk.date), context)
talk.location?.let {
if (it.isEmpty().not()) {
dateAndLocation = dateAndLocation + ", " + talk.location
if (dateAndLocation.isEmpty()) {
dateAndLocation = talk.location!!
}
}
}
holder.date.text = dateAndLocation
holder.icon.setFrontText((talk.title[0] + "").toUpperCase())
lastPosition = position
}
private fun getDate(date: Date, context: Context): String {
val dateFormat = android.text.format.DateFormat.getDateFormat(context)
return dateFormat.format(date)
}
override fun getModel(): Talk {
return talk
}
class TalkItemVH(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter) {
val icon: FlipView by lazy { itemView.findViewById<FlipView>(R.id.icon) }
val title: TextView by lazy { itemView.findViewById<TextView>(R.id.title) }
val date: TextView by lazy { itemView.findViewById<TextView>(R.id.date) }
val speaker: TextView by lazy { itemView.findViewById<TextView>(R.id.speaker) }
val owner: TextView by lazy { itemView.findViewById<TextView>(R.id.owner) }
init {
icon.setOnClickListener {
adapter.mItemLongClickListener.onItemLongClick(adapterPosition)
toggleActivation()
}
}
override fun getFrontView(): View = itemView.findViewById(R.id.root)
override fun getRearLeftView(): View = itemView.findViewById(R.id.rear_left_view)
override fun getRearRightView(): View = itemView.findViewById(R.id.rear_right_view)
}
companion object {
private const val TAG = "ITalk"
private val log = Log(TAG)
fun getTalks(iTalks: List<ITalk>): ArrayList<Talk> = iTalks.mapTo(ArrayList()) { it.talk }
@JvmField
val CREATOR: Parcelable.Creator<ITalk> = object : Parcelable.Creator<ITalk> {
override fun createFromParcel(source: Parcel): ITalk = ITalk(source)
override fun newArray(size: Int): Array<ITalk?> = arrayOfNulls(size)
}
}
constructor(source: Parcel) : this(
source.readParcelable<Talk>(Talk::class.java.classLoader)
)
override fun describeContents() = 0
override fun writeToParcel(dest: Parcel, flags: Int) {
dest.writeParcelable(talk, 0)
}
}
package eu.long1.jwnotes.fragments
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.support.design.widget.Snackbar
import android.support.v4.app.Fragment
import android.support.v4.widget.SwipeRefreshLayout
import android.support.v7.app.AppCompatActivity
import android.support.v7.view.ActionMode
import android.support.v7.widget.DividerItemDecoration
import android.support.v7.widget.helper.ItemTouchHelper
import android.view.*
import android.widget.Toast
import com.evernote.android.state.State
import com.firebase.ui.auth.AuthUI
import com.firebase.ui.auth.ui.ExtraConstants
import com.firebase.ui.auth.ui.FlowParameters
import com.google.firebase.FirebaseApp
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.SelectableAdapter.Mode.IDLE
import eu.davidea.flexibleadapter.SelectableAdapter.Mode.MULTI
import eu.davidea.flexibleadapter.helpers.ActionModeHelper
import eu.long1.jwnotes.*
import eu.long1.jwnotes.activities.MainActivity
import eu.long1.jwnotes.adapters.TalkAdapter
import eu.long1.jwnotes.custom.views.LinearLayoutManager
import eu.long1.jwnotes.custom.views.RecyclerView
import eu.long1.jwnotes.data.tables.TalkTable
import eu.long1.jwnotes.events.*
import eu.long1.jwnotes.helpers.Generic
import eu.long1.jwnotes.helpers.MainActivityHelper.finishActionMode
import eu.long1.jwnotes.helpers.MainActivityHelper.prepareForActionMode
import eu.long1.jwnotes.helpers.Preferences
import eu.long1.jwnotes.helpers.SnackbarHelper.showDeleteTalkSnackbar
import eu.long1.jwnotes.helpers.firebase.DatabaseH
import eu.long1.jwnotes.loaders.FirebaseStorageSync
import eu.long1.jwnotes.models.firebase.Talk
import eu.long1.jwnotes.models.firebase.User
import eu.long1.jwnotes.models.flexible.ITalk
import eu.long1.jwnotes.ui.phone.PhoneVerificationActivity
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.fragment_main.*
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
class MainFragment : Fragment(), SwipeRefreshLayout.OnRefreshListener, RecyclerView.EmptyViewListener,
ActionMode.Callback, FlexibleAdapter.OnItemClickListener, FlexibleAdapter.OnItemLongClickListener,
FlexibleAdapter.OnItemSwipeListener {
@State
var category = Talk.CATEGORY_MEETINGS
private val mActionModeHelper: ActionModeHelper by lazy {
ActionModeHelper(adapter, R.menu.fragment_main_action_mode_menu, this)
}
val adapter: TalkAdapter by lazy {
TalkAdapter(TalkTable.instance.list(category), this, category)
}
private var waitingTalks: ArrayList<Talk>? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
inflater.inflate(R.layout.fragment_main, container, false)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
onRestoreInstanceState(savedInstanceState)
recycler_view.layoutManager = LinearLayoutManager(activity)
recycler_view.setEmptyView(empty_view)
recycler_view.setEmptyViewListener(this)
recycler_view.adapter = adapter
recycler_view.addItemDecoration(DividerItemDecoration(activity, 1))
swipe_refresh_layout.setOnRefreshListener(this)
adapter.refreshAll()
}
override fun onRefresh() {
adapter.refreshAll()
if (!context.haveConnection()) {
Toast.makeText(context, R.string.no_connection, Toast.LENGTH_SHORT).show()
swipe_refresh_layout.isRefreshing = false
} else {
FirebaseStorageSync.sync()
}
}
private fun actionDelete(iTalks: List<ITalk>) {
adapter.deleteTalks(ITalk.getTalks(iTalks))
recycler_view.refreshEmptyViewState()
showDeleteTalkSnackbar(activity.coordinator_layout, iTalks.size, SnackCallback(), iTalks, { undoDelete(iTalks) })
}
@SuppressLint("RestrictedApi")
private fun actionShare(talks: ArrayList<Talk>) {
mActionModeHelper.destroyActionModeIfCan()
if (havePermission(android.Manifest.permission.READ_CONTACTS)) {
if (!User.getUserPhone().isNullOrEmpty()) {
EventBus.getDefault().postSticky(ShareTalksEvent(talks))
} else {
startActivityForResult(
PhoneVerificationActivity.createIntent(
context,
FlowParameters(
FirebaseApp.DEFAULT_APP_NAME,
arrayListOf(AuthUI.IdpConfig.Builder(AuthUI.PHONE_VERIFICATION_PROVIDER).build()),
AuthUI.getDefaultTheme(),
AuthUI.NO_LOGO,
null,
null,
true,
true,
true
)
),
PHONE_NUMBER_RC)
}
} else {
waitingTalks = talks
requestPermissions(arrayOf(android.Manifest.permission.READ_CONTACTS), CONTACTS_RC)
}
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
when (requestCode) {
CONTACTS_RC -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
waitingTalks?.let { actionShare(it) }
} else {
waitingTalks = null
context.longToast(getString(R.string.fragment_main_contacts_permission))
adapter.refreshAll()
}
return
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
log.e("onActivityResult $requestCode $resultCode $data")
when (requestCode) {
PHONE_NUMBER_RC -> if (resultCode == Activity.RESULT_OK) {
data?.getStringExtra(ExtraConstants.EXTRA_PHONE).let {
Preferences.getUserPreferences().edit().putString(Preferences.USER_PHONE_NUMBER, it).apply()
DatabaseH.userPhoneNumber.setValue(it)
waitingTalks?.let { actionShare(it) }
}
}
}
}
private fun startActionMode() {
mActionModeHelper.withDefaultMode(MULTI)
}
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
adapter.isSwipeEnabled = false
swipe_refresh_layout.isEnabled = false
prepareForActionMode(activity)
(activity as MainActivity).lockDrawer(false)
return true
}
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean = false
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
val iTalks = adapter.selectedTalks
mActionModeHelper.destroyActionModeIfCan()
when (item.itemId) {
R.id.item_share -> actionShare(ITalk.getTalks(iTalks))
R.id.item_delete -> actionDelete(iTalks)
}
return true
}
override fun onDestroyActionMode(mode: ActionMode) {
swipe_refresh_layout.isEnabled = true
adapter.isSwipeEnabled = true
adapter.refreshSelected()
finishActionMode(activity)
(activity as MainActivity).unlockDrawer()
}
override fun onItemClick(position: Int): Boolean {
return if (adapter.mode != IDLE) {
mActionModeHelper.onClick(position)
} else {
val talk = adapter.getItem(position)!!.model
EventBus.getDefault().post(OpenTalkEvent(talk))
false
}
}
override fun onItemLongClick(position: Int) {
startActionMode()
mActionModeHelper.onLongClick(activity as AppCompatActivity, position)
}
override fun onActionStateChanged(viewHolder: android.support.v7.widget.RecyclerView.ViewHolder?, actionState: Int) {
}
override fun onItemSwipe(position: Int, direction: Int) {
when (direction) {
ItemTouchHelper.LEFT -> showDeleteSnackBar(position)
ItemTouchHelper.RIGHT -> {
val talks = ArrayList<Talk>()
talks.add(adapter.getItem(position)!!.model)
actionShare(talks)
}
}
}
private fun showDeleteSnackBar(position: Int) {
val iTalks = ArrayList<ITalk>()
iTalks.add(adapter.getItem(position)!!)
adapter.removeItem(position)
recycler_view!!.refreshEmptyViewState()
showDeleteTalkSnackbar(activity.findViewById(R.id.coordinator_layout), 1,
SnackCallback(), iTalks) { undoDelete(iTalks) }
}
private fun undoDelete(iTalks: List<ITalk>) {
adapter.resetTalksToPosition(iTalks)
recycler_view.refreshEmptyViewState()
recycler_view.scrollToPosition(0)
}
override fun onEmptyView(visible: Boolean) {
if (!visible) return
empty_text.text = Generic.getCategoryEmptyText(context, category)
empty_image.setImageResource(Generic.getCategoryEmptyImage(category))
}
override fun onSaveInstanceState(outState: Bundle?) {
adapter.onSaveInstanceState(outState)
super.onSaveInstanceState(outState)
}
fun onRestoreInstanceState(savedInstanceState: Bundle?) {
if (savedInstanceState != null) {
adapter.onRestoreInstanceState(savedInstanceState)
if (adapter.selectedItemCount > 0) {
startActionMode()
mActionModeHelper.restoreSelection(activity as AppCompatActivity)
}
}
}
inner class SnackCallback : Snackbar.Callback() {
@Suppress("UNCHECKED_CAST")
override fun onDismissed(snackbar: Snackbar, event: Int) = when (event) {
Snackbar.Callback.DISMISS_EVENT_SWIPE, Snackbar.Callback.DISMISS_EVENT_TIMEOUT -> {
val talks = (snackbar.view.tag as ArrayList<ITalk>).map { it.model } as ArrayList<Talk>
FirebaseStorageSync.delete(talks)
Unit
}
else -> Unit
}
}
companion object {
val TAG = "MainFragment"
private val log = Log(TAG)
private const val CONTACTS_RC = 100
private const val PHONE_NUMBER_RC = 300
}
}
package eu.long1.jwnotes.adapters
import android.support.v7.widget.RecyclerView
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.long1.jwnotes.Log
import eu.long1.jwnotes.data.tables.TalkTable
import eu.long1.jwnotes.models.firebase.Talk
import eu.long1.jwnotes.models.flexible.ITalk
import java.util.*
class TalkAdapter(items: List<ITalk>, listeners: Any, private var currentCategory: Long) :
FlexibleAdapter<ITalk>(items, listeners) {
override fun onAttachedToRecyclerView(recyclerView: RecyclerView?) {
super.onAttachedToRecyclerView(recyclerView)
isSwipeEnabled = true
}
fun addTalk(talk: Talk) {
val iTalk = ITalk(talk)
if (contains(iTalk)) {
log.d("Dataset already contains " + talk)
return
}
if (currentCategory != talk.category) {
log.d("Talk not from this category")
return
}
addItem(0, iTalk)
}
fun resetTalksToPosition(talks: List<ITalk>) {
talks.forEach { addItem(it.lastPosition, it) }
}
fun deleteTalk(talk: Talk) {
val iTalk = ITalk(talk)
if (currentCategory != talk.category) {
log.d("Talk not from this category")
return
}
val index = getGlobalPositionOf(iTalk)
if (index == -1) return
removeItem(index)
}
fun updateTalk(talk: Talk) {
val iTalk = ITalk(talk)
if (currentCategory != talk.category) {
log.d("Talk not from this category")
val index = getGlobalPositionOf(iTalk)
if (index != -1) {
log.d("But it was in this list and we removed it.")
removeItem(index)
}
return
}
updateItem(0, iTalk, null)
}
fun addTalks(talks: ArrayList<Talk>) {
for (talk in talks) addTalk(talk)
}
fun deleteTalks(talks: ArrayList<Talk>) {
for (talk in talks) deleteTalk(talk)
}
fun updateTalks(talks: ArrayList<Talk>) {
for (talk in talks) updateTalk(talk)
}
fun refreshAll() {
updateDataSet(TalkTable.instance.list(currentCategory), false)
}
fun refreshCategory(category: Long) {
currentCategory = category
refreshAll()
}
fun refreshSelected() {
selectedPositions.forEach {
toggleSelection(it)
notifyItemChanged(it, true)
log.d(it)
}
}
override fun onCreateBubbleText(position: Int): String {
return getItem(position)!!.model.fileName[0].toString()
}
val selectedTalks: List<ITalk> get() = selectedPositions.map { getItem(it)!! }
companion object {
private val TAG = TalkAdapter::class.java.simpleName
private val log = Log(TAG)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment