CreateChannelFragment.kt
package chat.rocket.android.createchannel.ui
import android.os.Bundle
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.ActionMode
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.createchannel.presentation.CreateChannelPresenter
import chat.rocket.android.createchannel.presentation.CreateChannelView
import chat.rocket.android.members.adapter.MembersAdapter
import chat.rocket.android.members.uimodel.MemberUiModel
import chat.rocket.android.util.extension.asObservable
import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.ui
import chat.rocket.common.model.RoomType
import chat.rocket.common.model.roomTypeOf
import com.google.android.material.chip.Chip
import dagger.android.support.AndroidSupportInjection
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.app_bar.*
import kotlinx.android.synthetic.main.fragment_create_channel.*
import java.util.concurrent.TimeUnit
import javax.inject.Inject
internal const val TAG_CREATE_CHANNEL_FRAGMENT = "CreateChannelFragment"
fun newInstance() = CreateChannelFragment()
class CreateChannelFragment : Fragment(), CreateChannelView, ActionMode.Callback {
@Inject lateinit var presenter: CreateChannelPresenter
@Inject lateinit var analyticsManager: AnalyticsManager
private var actionMode: ActionMode? = null
private val adapter: MembersAdapter = MembersAdapter {
it.username?.run { processSelectedMember(this) }
}
private val compositeDisposable = CompositeDisposable()
private var channelType: String = RoomType.CHANNEL
private var isChannelReadOnly: Boolean = false
private var memberList = arrayListOf<String>()
override fun onCreate(savedInstanceState: Bundle?) {
AndroidSupportInjection.inject(this)
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? = container?.inflate(R.layout.fragment_create_channel)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupToolBar()
setupViewListeners()
setupRecyclerView()
subscribeEditTexts()
analyticsManager.logScreenView(ScreenViewEvent.CreateChannel)
}
override fun onDestroyView() {
super.onDestroyView()
unsubscribeEditTexts()
}
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
mode.menuInflater.inflate(R.menu.create_channel, menu)
mode.title = getString(R.string.title_create_channel)
return true
}
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean = false
override fun onActionItemClicked(mode: ActionMode, menuItem: MenuItem): Boolean {
return when (menuItem.itemId) {
R.id.action_create_channel -> {
presenter.createChannel(
roomTypeOf(channelType),
text_channel_name.text.toString(),
memberList,
isChannelReadOnly
)
mode.finish()
true
}
else -> {
false
}
}
}
override fun onDestroyActionMode(mode: ActionMode) {
actionMode = null
}
override fun showLoading() {
ui {
view_loading.isVisible = true
}
}
override fun hideLoading() {
ui {
view_loading.isVisible = false
}
}
override fun showMessage(resId: Int) {
ui {
showToast(resId)
}
}
override fun showMessage(message: String) {
ui {
showToast(message)
}
}
override fun showGenericErrorMessage() {
showMessage(getString(R.string.msg_generic_error))
}
override fun showUserSuggestion(dataSet: List<MemberUiModel>) {
adapter.clearData()
adapter.prependData(dataSet)
text_member_not_found.isVisible = false
recycler_view.isVisible = true
view_member_suggestion.isVisible = true
}
override fun showNoUserSuggestion() {
recycler_view.isVisible = false
text_member_not_found.isVisible = true
view_member_suggestion.isVisible = true
}
override fun showSuggestionViewInProgress() {
recycler_view.isVisible = false
text_member_not_found.isVisible = false
view_member_suggestion_loading.isVisible = true
view_member_suggestion.isVisible = true
}
override fun hideSuggestionViewInProgress() {
view_member_suggestion_loading.isVisible = false
}
override fun showChannelCreatedSuccessfullyMessage() {
showMessage(getString(R.string.msg_channel_created_successfully))
}
override fun enableUserInput() {
text_channel_name.isEnabled = true
text_invite_members.isEnabled = true
}
override fun disableUserInput() {
text_channel_name.isEnabled = false
text_invite_members.isEnabled = false
}
private fun setupToolBar() {
with((activity as AppCompatActivity)) {
with(toolbar) {
setSupportActionBar(this)
title = getString(R.string.title_create_channel)
setNavigationIcon(R.drawable.ic_arrow_back_white_24dp)
setNavigationOnClickListener { activity?.onBackPressed() }
}
}
}
private fun setupViewListeners() {
switch_channel_type.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
text_channel_type.text = getString(R.string.msg_private_channel)
text_channel_type_description.text =
getString(R.string.msg_private_channel_description)
image_channel_icon.setImageDrawable(
context?.getDrawable(R.drawable.ic_lock_black_12_dp)
)
channelType = RoomType.PRIVATE_GROUP
} else {
text_channel_type.text = getString(R.string.msg_public_channel)
text_channel_type_description.text =
getString(R.string.msg_public_channel_description)
image_channel_icon.setImageDrawable(
context?.getDrawable(R.drawable.ic_hashtag_black_12dp)
)
channelType = RoomType.CHANNEL
}
}
switch_read_only.setOnCheckedChangeListener { _, isChecked ->
isChannelReadOnly = isChecked
}
}
private fun setupRecyclerView() {
ui {
recycler_view.layoutManager =
LinearLayoutManager(context, RecyclerView.VERTICAL, false)
recycler_view.addItemDecoration(
DividerItemDecoration(it, DividerItemDecoration.HORIZONTAL)
)
recycler_view.adapter = adapter
}
}
private fun subscribeEditTexts() {
val channelNameDisposable = text_channel_name.asObservable()
.subscribe {
if (it.isNotBlank()) {
startActionMode()
} else {
finishActionMode()
}
}
val inviteMembersDisposable = text_invite_members.asObservable()
.debounce(300, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
.filter { t -> t.isNotBlank() }
.subscribe {
if (it.length >= 3) {
presenter.searchUser(it.toString())
} else {
view_member_suggestion.isVisible = false
}
}
compositeDisposable.addAll(channelNameDisposable, inviteMembersDisposable)
}
private fun unsubscribeEditTexts() {
compositeDisposable.dispose()
}
private fun startActionMode() {
if (actionMode == null) {
actionMode = (activity as AppCompatActivity).startSupportActionMode(this)
}
}
private fun finishActionMode() {
actionMode?.finish()
}
private fun processSelectedMember(username: String) {
if (memberList.contains(username)) {
showMessage(getString(R.string.msg_member_already_added))
} else {
view_member_suggestion.isVisible = false
text_invite_members.text.clear()
addMember(username)
addChip(username)
chip_group_member.isVisible = true
}
}
private fun addMember(username: String) {
memberList.add(username)
}
private fun removeMember(username: String) {
memberList.remove(username)
}
private fun addChip(chipText: String) {
val chip = Chip(context)
chip.text = chipText
chip.isCloseIconVisible = true
chip.setChipBackgroundColorResource(R.color.icon_grey)
setupChipOnCloseIconClickListener(chip)
chip_group_member.addView(chip)
}
private fun setupChipOnCloseIconClickListener(chip: Chip) {
chip.setOnCloseIconClickListener {
removeChip(it)
removeMember((it as Chip).text.toString())
// whenever we remove a chip we should process the chip group visibility.
processChipGroupVisibility()
}
}
private fun removeChip(chip: View) {
chip_group_member.removeView(chip)
}
private fun processChipGroupVisibility() {
chip_group_member.isVisible = memberList.isNotEmpty()
}
}