-
Notifications
You must be signed in to change notification settings - Fork 552
[NEW] Add bottomSheet for members #2002
base: develop
Are you sure you want to change the base?
Changes from all commits
ade0317
f5d8e22
d7aaf98
cedf828
793e2cc
0839e81
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,8 +35,9 @@ fun newInstance( | |
chatRoomId: String, | ||
chatRoomType: String, | ||
isSubscribed: Boolean, | ||
isFavorite: Boolean, | ||
disableMenu: Boolean | ||
disableMenu: Boolean, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, I think you wrong deleted the isFavorite param here. |
||
isOwner: Boolean, | ||
isMod: Boolean | ||
): ChatDetailsFragment { | ||
return ChatDetailsFragment().apply { | ||
arguments = Bundle(5).apply { | ||
|
@@ -45,6 +46,8 @@ fun newInstance( | |
putBoolean(BUNDLE_IS_SUBSCRIBED, isSubscribed) | ||
putBoolean(BUNDLE_IS_FAVORITE, isFavorite) | ||
putBoolean(BUNDLE_DISABLE_MENU, disableMenu) | ||
putBoolean(BUNDLE_CHAT_ROOM_OWNER, isOwner) | ||
putBoolean(BUNDLE_CHAT_ROOM_MOD, isMod) | ||
} | ||
} | ||
} | ||
|
@@ -54,6 +57,8 @@ internal const val MENU_ACTION_FAVORITE_REMOVE_FAVORITE = 1 | |
internal const val MENU_ACTION_VIDEO_CALL = 2 | ||
|
||
private const val BUNDLE_CHAT_ROOM_ID = "BUNDLE_CHAT_ROOM_ID" | ||
private const val BUNDLE_CHAT_ROOM_MOD = "BUNDLE_CHAT_ROOM_MOD" | ||
private const val BUNDLE_CHAT_ROOM_OWNER = "BUNDLE_CHAT_ROOM_OWNER" | ||
private const val BUNDLE_CHAT_ROOM_TYPE = "BUNDLE_CHAT_ROOM_TYPE" | ||
private const val BUNDLE_IS_SUBSCRIBED = "BUNDLE_IS_SUBSCRIBED" | ||
private const val BUNDLE_IS_FAVORITE = "BUNDLE_IS_FAVORITE" | ||
|
@@ -74,22 +79,24 @@ class ChatDetailsFragment : Fragment(), ChatDetailsView { | |
internal lateinit var chatRoomId: String | ||
internal lateinit var chatRoomType: String | ||
private var isSubscribed: Boolean = true | ||
internal var isFavorite: Boolean = false | ||
private var isOwner: Boolean = false | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where is the isFavorite param? |
||
private var isMod: Boolean = false | ||
private var disableMenu: Boolean = false | ||
|
||
override fun onCreate(savedInstanceState: Bundle?) { | ||
super.onCreate(savedInstanceState) | ||
AndroidSupportInjection.inject(this) | ||
|
||
arguments?.run { | ||
chatRoomId = getString(BUNDLE_CHAT_ROOM_ID) | ||
chatRoomType = getString(BUNDLE_CHAT_ROOM_TYPE) | ||
isSubscribed = getBoolean(BUNDLE_IS_SUBSCRIBED) | ||
isFavorite = getBoolean(BUNDLE_IS_FAVORITE) | ||
disableMenu = getBoolean(BUNDLE_DISABLE_MENU) | ||
} ?: requireNotNull(arguments) { "no arguments supplied when the fragment was instantiated" } | ||
|
||
setHasOptionsMenu(true) | ||
val bundle = arguments | ||
if (bundle != null) { | ||
chatRoomId = bundle.getString(BUNDLE_CHAT_ROOM_ID) | ||
chatRoomType = bundle.getString(BUNDLE_CHAT_ROOM_TYPE) | ||
isSubscribed = bundle.getBoolean(BUNDLE_IS_SUBSCRIBED) | ||
disableMenu = bundle.getBoolean(BUNDLE_DISABLE_MENU) | ||
isOwner = bundle.getBoolean(BUNDLE_CHAT_ROOM_OWNER) | ||
isMod = bundle.getBoolean(BUNDLE_CHAT_ROOM_MOD) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where is the isFavorite param? We have a bundle for it. |
||
} else { | ||
requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" } | ||
} | ||
} | ||
|
||
override fun onCreateView( | ||
|
@@ -166,7 +173,7 @@ class ChatDetailsFragment : Fragment(), ChatDetailsView { | |
getString(R.string.title_members), | ||
R.drawable.ic_people_outline_black_24dp | ||
) { | ||
presenter.toMembers(chatRoomId!!) | ||
presenter.toMembers(chatRoomId!!, isOwner, isMod) | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -67,23 +67,25 @@ class ChatRoomNavigator(internal val activity: ChatRoomActivity) { | |
chatRoomId: String, | ||
chatRoomType: String, | ||
isChatRoomSubscribed: Boolean, | ||
isChatRoomFavorite: Boolean, | ||
isMenuDisabled: Boolean | ||
isMenuDisabled: Boolean, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where is the isFavorite param? |
||
isOwner: Boolean, | ||
isModerator: Boolean | ||
) { | ||
activity.addFragmentBackStack(TAG_CHAT_DETAILS_FRAGMENT, R.id.fragment_container) { | ||
chat.rocket.android.chatdetails.ui.newInstance( | ||
chatRoomId, | ||
chatRoomType, | ||
isChatRoomSubscribed, | ||
isChatRoomFavorite, | ||
isMenuDisabled | ||
isMenuDisabled, | ||
isOwner, | ||
isModerator | ||
) | ||
} | ||
} | ||
|
||
fun toMembersList(chatRoomId: String) { | ||
fun toMembersList(chatRoomId: String, isOwner: Boolean, isMod: Boolean) { | ||
activity.addFragmentBackStack(TAG_MEMBERS_FRAGMENT, R.id.fragment_container) { | ||
chat.rocket.android.members.ui.newInstance(chatRoomId) | ||
chat.rocket.android.members.ui.newInstance(chatRoomId, isOwner, isMod) | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -144,7 +144,7 @@ class ChatRoomPresenter @Inject constructor( | |
chatRoles = emptyList() | ||
} finally { | ||
// User has at least an 'owner' or 'moderator' role. | ||
val canModerate = isOwnerOrMod() | ||
val canModerate = isOwner() || isModerator() | ||
// Can post anyway if has the 'post-readonly' permission on server. | ||
val room = dbManager.getRoom(roomId) | ||
room?.let { | ||
|
@@ -192,9 +192,15 @@ class ChatRoomPresenter @Inject constructor( | |
chatRoomId?.let { manager.removeRoomChannel(it) } | ||
} | ||
|
||
private fun isOwnerOrMod(): Boolean { | ||
return chatRoles.firstOrNull { it.user.username == currentLoggedUsername }?.roles?.any { | ||
it == "owner" || it == "moderator" | ||
private fun isOwner(): Boolean { | ||
return chatRoles.find { it.user.username == currentLoggedUsername }?.roles?.any { | ||
it == "owner" | ||
} ?: false | ||
} | ||
|
||
private fun isModerator(): Boolean { | ||
return chatRoles.find { it.user.username == currentLoggedUsername }?.roles?.any { | ||
it == "moderator" | ||
} ?: false | ||
} | ||
|
||
|
@@ -896,7 +902,7 @@ class ChatRoomPresenter @Inject constructor( | |
isFavorite: Boolean, | ||
isMenuDisabled: Boolean | ||
) { | ||
navigator.toChatDetails(chatRoomId, chatRoomType, isSubscribed, isFavorite, isMenuDisabled) | ||
navigator.toChatDetails(chatRoomId, chatRoomType, isSubscribed, isMenuDisabled, isOwner(), isModerator()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where is the isFavorite param? |
||
} | ||
|
||
fun loadChatRoomsSuggestions() { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,9 +44,11 @@ class CreateChannelFragment : Fragment(), CreateChannelView, ActionMode.Callback | |
@Inject | ||
lateinit var analyticsManager: AnalyticsManager | ||
private var actionMode: ActionMode? = null | ||
private val adapter: MembersAdapter = MembersAdapter { | ||
it.username?.run { processSelectedMember(this) } | ||
} | ||
private val adapter: MembersAdapter = MembersAdapter ({ | ||
if (it.username != null) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why doing it instead of |
||
processSelectedMember(it.username) | ||
} | ||
}, null, true, false) | ||
private val compositeDisposable = CompositeDisposable() | ||
private var channelType: String = RoomType.CHANNEL | ||
private var isChannelReadOnly: Boolean = false | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,24 @@ | ||
package chat.rocket.android.members.adapter | ||
|
||
import android.view.View | ||
import android.util.Log | ||
import android.view.MenuItem | ||
import android.view.ViewGroup | ||
import androidx.recyclerview.widget.RecyclerView | ||
import chat.rocket.android.R | ||
import chat.rocket.android.members.presentation.MembersPresenter | ||
import chat.rocket.android.members.uimodel.MemberUiModel | ||
import chat.rocket.android.util.extensions.content | ||
import chat.rocket.android.util.extensions.inflate | ||
import kotlinx.android.synthetic.main.avatar.view.* | ||
import kotlinx.android.synthetic.main.item_member.view.* | ||
|
||
class MembersAdapter( | ||
private val listener: (MemberUiModel) -> Unit | ||
) : RecyclerView.Adapter<MembersAdapter.ViewHolder>() { | ||
class MembersAdapter(private val listener: (MemberUiModel) -> Unit, presenter: MembersPresenter?, private val isOwner: Boolean, private val isMod: Boolean) : | ||
RecyclerView.Adapter<ViewHolder>() { | ||
private var dataSet: List<MemberUiModel> = ArrayList() | ||
private val enableActions: Boolean = true | ||
|
||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MembersAdapter.ViewHolder = | ||
ViewHolder(parent.inflate(R.layout.item_member)) | ||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder = | ||
ViewHolder(parent.inflate(R.layout.item_member), actionsListener, isOwner, isMod) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
override fun onBindViewHolder(holder: MembersAdapter.ViewHolder, position: Int) = | ||
holder.bind(dataSet[position], listener) | ||
override fun onBindViewHolder(holder: ViewHolder, position: Int) = | ||
holder.bind(dataSet[position], position, listener) | ||
|
||
override fun getItemCount(): Int = dataSet.size | ||
|
||
|
@@ -39,14 +38,57 @@ class MembersAdapter( | |
notifyItemRangeInserted(previousDataSetSize, dataSet.size) | ||
} | ||
|
||
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { | ||
|
||
fun bind(memberUiModel: MemberUiModel, listener: (MemberUiModel) -> Unit) = with(itemView) { | ||
image_avatar.setImageURI(memberUiModel.avatarUri) | ||
text_member.content = memberUiModel.displayName | ||
text_member.setCompoundDrawablesRelativeWithIntrinsicBounds( | ||
DrawableHelper.getUserStatusDrawable(memberUiModel.status, context), null, null, null) | ||
setOnClickListener { listener(memberUiModel) } | ||
private val actionsListener = object : ViewHolder.ActionsListener { | ||
override fun isActionsEnabled(): Boolean = enableActions | ||
override fun onActionSelected(item: MenuItem, member: MemberUiModel, index: Int) { | ||
member.apply { | ||
when (item.itemId) { | ||
R.id.action_member_set_owner-> { | ||
val isOwner = this.roles?.contains("owner") == true | ||
presenter?.toggleOwner(this.userId, isOwner) { | ||
if (isOwner) | ||
dataSet[index].roles = dataSet[index].roles?.filterNot { it == "owner"} | ||
else | ||
dataSet[index].roles = dataSet[index].roles?.plus("owner") | ||
notifyItemChanged(index) | ||
} | ||
} | ||
R.id.action_member_set_leader-> { | ||
val isLeader = this.roles?.contains("leader") == true | ||
presenter?.toggleLeader(this.userId, isLeader) { | ||
if (isLeader) | ||
dataSet[index].roles = dataSet[index].roles?.filterNot { it == "leader"} | ||
else | ||
dataSet[index].roles = dataSet[index].roles?.plus("leader") | ||
notifyItemChanged(index) | ||
} | ||
} | ||
R.id.action_member_set_moderator-> { | ||
val isMod = this.roles?.contains("moderator") == true | ||
presenter?.toggleModerator(this.userId, isMod) { | ||
if (isMod) | ||
dataSet[index].roles = dataSet[index].roles?.filterNot { it == "moderator" } | ||
else | ||
dataSet[index].roles = dataSet[index].roles?.plus("moderator") | ||
notifyItemChanged(index) | ||
} | ||
} | ||
R.id.action_member_mute-> { | ||
presenter?.toggleMute(this.username, this.muted) { | ||
dataSet[index].muted = !this.muted | ||
notifyItemChanged(index) | ||
} | ||
} | ||
R.id.action_member_remove-> { | ||
presenter?.removeUser(this.userId) { | ||
dataSet = dataSet.filterIndexed{ position, _-> position != index } | ||
notifyItemRemoved(index) | ||
notifyItemRangeChanged(index, dataSet.size) | ||
} | ||
} | ||
else -> TODO("Not implemented") | ||
} | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package chat.rocket.android.members.adapter | ||
|
||
import android.view.ContextThemeWrapper | ||
import android.view.MenuItem | ||
import android.view.View | ||
import androidx.appcompat.app.AppCompatActivity | ||
import androidx.core.view.isVisible | ||
import androidx.lifecycle.Lifecycle | ||
import androidx.recyclerview.widget.RecyclerView | ||
import chat.rocket.android.R | ||
import chat.rocket.android.members.ui.GroupMemberBottomSheet | ||
import chat.rocket.android.members.uimodel.MemberUiModel | ||
import chat.rocket.android.util.extensions.content | ||
import chat.rocket.android.util.extensions.inflate | ||
import chat.rocket.android.util.extensions.toList | ||
import kotlinx.android.synthetic.main.avatar.view.* | ||
import kotlinx.android.synthetic.main.item_member.view.* | ||
|
||
|
||
class ViewHolder( | ||
itemView: View, | ||
private val listener: ActionsListener, | ||
private val isOwner: Boolean, | ||
private val isMod: Boolean | ||
) : RecyclerView.ViewHolder(itemView), MenuItem.OnMenuItemClickListener { | ||
var data: MemberUiModel? = null | ||
var index: Int = 0 | ||
|
||
fun bind(memberUiModel: MemberUiModel, position: Int, listener: (MemberUiModel) -> Unit) = with(itemView) { | ||
data = memberUiModel | ||
index = position | ||
image_avatar.setImageURI(memberUiModel.avatarUri) | ||
text_member.content = memberUiModel.displayName | ||
text_member.setCompoundDrawablesRelativeWithIntrinsicBounds(DrawableHelper.getUserStatusDrawable(memberUiModel.status, context), null, null, null) | ||
text_member_owner.setText(R.string.owner) | ||
text_member_leader.setText(R.string.leader) | ||
text_member_moderator.setText(R.string.moderator) | ||
text_member_owner.isVisible =memberUiModel.roles?.contains("owner") == true | ||
text_member_leader.isVisible = memberUiModel.roles?.contains("leader") == true | ||
text_member_moderator.isVisible = memberUiModel.roles?.contains("moderator") == true | ||
setOnClickListener { listener(memberUiModel) } | ||
setupActionMenu(itemView) | ||
} | ||
|
||
interface ActionsListener { | ||
fun isActionsEnabled(): Boolean | ||
fun onActionSelected(item: MenuItem, member: MemberUiModel, index: Int) | ||
} | ||
|
||
internal fun setupActionMenu(view: View) { | ||
view.setOnLongClickListener{ | ||
data?.let { | ||
var menuItems = view.context.inflate(R.menu.group_member_actions).toList() | ||
if (!isOwner && !isMod) | ||
menuItems = menuItems.filter { it.itemId == R.id.action_member_mute } | ||
else if (!isOwner && isMod) | ||
menuItems = menuItems.filter { it.itemId == R.id.action_member_mute || it.itemId == R.id.action_member_remove} | ||
menuItems.find { it.itemId == R.id.action_member_set_owner }?.apply { | ||
if (it.roles?.contains("owner") == true) setTitle(R.string.action_remove_owner) | ||
} | ||
menuItems.find { it.itemId == R.id.action_member_set_leader }?.apply { | ||
if (it.roles?.contains("leader") == true) setTitle(R.string.action_remove_leader) | ||
} | ||
menuItems.find { it.itemId == R.id.action_member_set_moderator }?.apply { | ||
if (it.roles?.contains("moderator") == true) setTitle(R.string.action_remove_moderator) | ||
} | ||
menuItems.find { it.itemId == R.id.action_member_mute }?.apply { | ||
if (it.muted) { | ||
setTitle(R.string.action_unmute_user) | ||
setIcon(R.drawable.ic_mic_on_24dp) | ||
} | ||
} | ||
// TODO: Check why ignore is not working | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you going to check it? |
||
// menuItems.find { it.itemId == R.id.action_member_ignore }?.apply { | ||
// if (it.roles.contains("owner")) title = "Remove Owner" | ||
// } | ||
view.context?.let { | ||
if (it is ContextThemeWrapper && it.baseContext is AppCompatActivity) { | ||
with(it.baseContext as AppCompatActivity) { | ||
if (this.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) { | ||
val actionsBottomSheet = GroupMemberBottomSheet() | ||
actionsBottomSheet.addItems(menuItems, this@ViewHolder) | ||
actionsBottomSheet.show(supportFragmentManager, null) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
true | ||
} | ||
} | ||
|
||
override fun onMenuItemClick(item: MenuItem): Boolean { | ||
data?.let { | ||
listener.onActionSelected(item, it, index) | ||
} | ||
return true | ||
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isModerator
sounds better thanisMod
. You have even created a function with that name onChatRoomPresenter.kt
for instance.