Commit f14e01f3 authored by Leonardo Aramaki's avatar Leonardo Aramaki

Add autocomplete to commands

parent 07a613d3
package chat.rocket.android.chatroom.adapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import chat.rocket.android.R
import chat.rocket.android.chatroom.adapter.CommandSuggestionsAdapter.CommandSuggestionsViewHolder
import chat.rocket.android.chatroom.viewmodel.suggestion.CommandSuggestionViewModel
import chat.rocket.android.widget.autocompletion.model.SuggestionModel
import chat.rocket.android.widget.autocompletion.ui.BaseSuggestionViewHolder
import chat.rocket.android.widget.autocompletion.ui.SuggestionsAdapter
class CommandSuggestionsAdapter : SuggestionsAdapter<CommandSuggestionsViewHolder>("/") {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CommandSuggestionsViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.suggestion_command_item, parent,
false)
return CommandSuggestionsViewHolder(view)
}
class CommandSuggestionsViewHolder(view: View) : BaseSuggestionViewHolder(view) {
override fun bind(item: SuggestionModel, itemClickListener: SuggestionsAdapter.ItemClickListener?) {
item as CommandSuggestionViewModel
with(itemView) {
val nameTextView = itemView.findViewById<TextView>(R.id.text_command_name)
val descriptionTextView = itemView.findViewById<TextView>(R.id.text_command_description)
nameTextView.text = item.text
descriptionTextView.text = item.description
setOnClickListener {
itemClickListener?.onClick(item)
}
}
}
}
}
\ No newline at end of file
...@@ -8,7 +8,7 @@ import android.widget.ImageView ...@@ -8,7 +8,7 @@ import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.chatroom.adapter.PeopleSuggestionsAdapter.PeopleSuggestionViewHolder import chat.rocket.android.chatroom.adapter.PeopleSuggestionsAdapter.PeopleSuggestionViewHolder
import chat.rocket.android.chatroom.viewmodel.PeopleViewModel import chat.rocket.android.chatroom.viewmodel.suggestion.PeopleSuggestionViewModel
import chat.rocket.android.util.extensions.setVisible import chat.rocket.android.util.extensions.setVisible
import chat.rocket.android.widget.autocompletion.model.SuggestionModel import chat.rocket.android.widget.autocompletion.model.SuggestionModel
import chat.rocket.android.widget.autocompletion.ui.BaseSuggestionViewHolder import chat.rocket.android.widget.autocompletion.ui.BaseSuggestionViewHolder
...@@ -26,7 +26,7 @@ class PeopleSuggestionsAdapter : SuggestionsAdapter<PeopleSuggestionViewHolder>( ...@@ -26,7 +26,7 @@ class PeopleSuggestionsAdapter : SuggestionsAdapter<PeopleSuggestionViewHolder>(
class PeopleSuggestionViewHolder(view: View) : BaseSuggestionViewHolder(view) { class PeopleSuggestionViewHolder(view: View) : BaseSuggestionViewHolder(view) {
override fun bind(item: SuggestionModel, itemClickListener: SuggestionsAdapter.ItemClickListener?) { override fun bind(item: SuggestionModel, itemClickListener: SuggestionsAdapter.ItemClickListener?) {
item as PeopleViewModel item as PeopleSuggestionViewModel
with(itemView) { with(itemView) {
val username = itemView.findViewById<TextView>(R.id.text_username) val username = itemView.findViewById<TextView>(R.id.text_username)
val name = itemView.findViewById<TextView>(R.id.text_name) val name = itemView.findViewById<TextView>(R.id.text_name)
......
...@@ -6,7 +6,7 @@ import android.view.ViewGroup ...@@ -6,7 +6,7 @@ import android.view.ViewGroup
import android.widget.TextView import android.widget.TextView
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.chatroom.adapter.RoomSuggestionsAdapter.RoomSuggestionsViewHolder import chat.rocket.android.chatroom.adapter.RoomSuggestionsAdapter.RoomSuggestionsViewHolder
import chat.rocket.android.chatroom.viewmodel.ChatRoomViewModel import chat.rocket.android.chatroom.viewmodel.suggestion.ChatRoomSuggestionViewModel
import chat.rocket.android.widget.autocompletion.model.SuggestionModel import chat.rocket.android.widget.autocompletion.model.SuggestionModel
import chat.rocket.android.widget.autocompletion.ui.BaseSuggestionViewHolder import chat.rocket.android.widget.autocompletion.ui.BaseSuggestionViewHolder
import chat.rocket.android.widget.autocompletion.ui.SuggestionsAdapter import chat.rocket.android.widget.autocompletion.ui.SuggestionsAdapter
...@@ -22,7 +22,7 @@ class RoomSuggestionsAdapter : SuggestionsAdapter<RoomSuggestionsViewHolder>("#" ...@@ -22,7 +22,7 @@ class RoomSuggestionsAdapter : SuggestionsAdapter<RoomSuggestionsViewHolder>("#"
class RoomSuggestionsViewHolder(view: View) : BaseSuggestionViewHolder(view) { class RoomSuggestionsViewHolder(view: View) : BaseSuggestionViewHolder(view) {
override fun bind(item: SuggestionModel, itemClickListener: SuggestionsAdapter.ItemClickListener?) { override fun bind(item: SuggestionModel, itemClickListener: SuggestionsAdapter.ItemClickListener?) {
item as ChatRoomViewModel item as ChatRoomSuggestionViewModel
with(itemView) { with(itemView) {
val fullname = itemView.findViewById<TextView>(R.id.text_fullname) val fullname = itemView.findViewById<TextView>(R.id.text_fullname)
val name = itemView.findViewById<TextView>(R.id.text_name) val name = itemView.findViewById<TextView>(R.id.text_name)
......
...@@ -6,9 +6,10 @@ import chat.rocket.android.chatroom.adapter.AutoCompleteType ...@@ -6,9 +6,10 @@ import chat.rocket.android.chatroom.adapter.AutoCompleteType
import chat.rocket.android.chatroom.adapter.PEOPLE import chat.rocket.android.chatroom.adapter.PEOPLE
import chat.rocket.android.chatroom.adapter.ROOMS import chat.rocket.android.chatroom.adapter.ROOMS
import chat.rocket.android.chatroom.domain.UriInteractor import chat.rocket.android.chatroom.domain.UriInteractor
import chat.rocket.android.chatroom.viewmodel.ChatRoomViewModel import chat.rocket.android.chatroom.viewmodel.suggestion.ChatRoomSuggestionViewModel
import chat.rocket.android.chatroom.viewmodel.PeopleViewModel import chat.rocket.android.chatroom.viewmodel.suggestion.PeopleSuggestionViewModel
import chat.rocket.android.chatroom.viewmodel.ViewModelMapper import chat.rocket.android.chatroom.viewmodel.ViewModelMapper
import chat.rocket.android.chatroom.viewmodel.suggestion.CommandSuggestionViewModel
import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.helper.UrlHelper import chat.rocket.android.helper.UrlHelper
import chat.rocket.android.infrastructure.LocalRepository import chat.rocket.android.infrastructure.LocalRepository
...@@ -363,7 +364,7 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView, ...@@ -363,7 +364,7 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
// Take at most the 100 most recent messages distinguished by user. Can return less. // Take at most the 100 most recent messages distinguished by user. Can return less.
val recentMessages = messagesRepository.getRecentMessages(chatRoomId, 100) val recentMessages = messagesRepository.getRecentMessages(chatRoomId, 100)
.filterNot { filterSelfOut && it.sender?.username == self } .filterNot { filterSelfOut && it.sender?.username == self }
val activeUsers = mutableListOf<PeopleViewModel>() val activeUsers = mutableListOf<PeopleSuggestionViewModel>()
recentMessages.forEach { recentMessages.forEach {
val sender = it.sender!! val sender = it.sender!!
val username = sender.username ?: "" val username = sender.username ?: ""
...@@ -372,7 +373,7 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView, ...@@ -372,7 +373,7 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
val found = members.firstOrNull { member -> member.username == username } val found = members.firstOrNull { member -> member.username == username }
val status = if (found != null) found.status else UserStatus.Offline() val status = if (found != null) found.status else UserStatus.Offline()
val searchList = mutableListOf(username, name) val searchList = mutableListOf(username, name)
activeUsers.add(PeopleViewModel(avatarUrl, username, username, name, status, activeUsers.add(PeopleSuggestionViewModel(avatarUrl, username, username, name, status,
true, searchList)) true, searchList))
} }
// Filter out from members list the active users. // Filter out from members list the active users.
...@@ -387,10 +388,10 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView, ...@@ -387,10 +388,10 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
val name = it.name ?: "" val name = it.name ?: ""
val avatarUrl = UrlHelper.getAvatarUrl(currentServer, username) val avatarUrl = UrlHelper.getAvatarUrl(currentServer, username)
val searchList = mutableListOf(username, name) val searchList = mutableListOf(username, name)
PeopleViewModel(avatarUrl, username, username, name, it.status, true, searchList) PeopleSuggestionViewModel(avatarUrl, username, username, name, it.status, true, searchList)
}) })
view.populateMembers(activeUsers) view.populatePeopleSuggestions(activeUsers)
} catch (e: RocketChatException) { } catch (e: RocketChatException) {
Timber.e(e) Timber.e(e)
} }
...@@ -407,12 +408,12 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView, ...@@ -407,12 +408,12 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
usersRepository.saveAll(users) usersRepository.saveAll(users)
} }
val self = localRepository.get(LocalRepository.USERNAME_KEY) val self = localRepository.get(LocalRepository.USERNAME_KEY)
view.populateMembers(users.map { view.populatePeopleSuggestions(users.map {
val username = it.username ?: "" val username = it.username ?: ""
val name = it.name ?: "" val name = it.name ?: ""
val searchList = mutableListOf(username, name) val searchList = mutableListOf(username, name)
it.emails?.forEach { email -> searchList.add(email.address) } it.emails?.forEach { email -> searchList.add(email.address) }
PeopleViewModel(UrlHelper.getAvatarUrl(currentServer, username), PeopleSuggestionViewModel(UrlHelper.getAvatarUrl(currentServer, username),
username, username, name, it.status, false, searchList) username, username, name, it.status, false, searchList)
}.filterNot { filterSelfOut && self != null && self == it.text }) }.filterNot { filterSelfOut && self != null && self == it.text })
} }
...@@ -420,11 +421,11 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView, ...@@ -420,11 +421,11 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
if (rooms.isNotEmpty()) { if (rooms.isNotEmpty()) {
roomsRepository.saveAll(rooms) roomsRepository.saveAll(rooms)
} }
view.populateRooms(rooms.map { view.populateRoomSuggestions(rooms.map {
val fullName = it.fullName ?: "" val fullName = it.fullName ?: ""
val name = it.name ?: "" val name = it.name ?: ""
val searchList = mutableListOf(fullName, name) val searchList = mutableListOf(fullName, name)
ChatRoomViewModel(name, fullName, name, searchList) ChatRoomSuggestionViewModel(name, fullName, name, searchList)
}) })
} }
} }
...@@ -446,14 +447,14 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView, ...@@ -446,14 +447,14 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
.map { chatRoom -> .map { chatRoom ->
val name = chatRoom.name val name = chatRoom.name
val fullName = chatRoom.fullName ?: "" val fullName = chatRoom.fullName ?: ""
ChatRoomViewModel( ChatRoomSuggestionViewModel(
text = name, text = name,
name = name, name = name,
fullName = fullName, fullName = fullName,
searchList = listOf(name, fullName) searchList = listOf(name, fullName)
) )
} }
view.populateRooms(chatRooms) view.populateRoomSuggestions(chatRooms)
} catch (e: RocketChatException) { } catch (e: RocketChatException) {
Timber.e(e) Timber.e(e)
} }
...@@ -488,6 +489,24 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView, ...@@ -488,6 +489,24 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
view.showReactionsPopup(messageId) view.showReactionsPopup(messageId)
} }
/**
* Loads the list of available commands.
*/
fun loadCommands(query: String = "") {
launchUI(strategy) {
try {
//TODO: cache the commands
val commands = client.commands(0, 100).result
view.populateCommandSuggestions(commands.map {
println(it)
CommandSuggestionViewModel(it.command, it.description ?: "", listOf(it.command))
})
} catch (ex: RocketChatException) {
Timber.e(ex)
}
}
}
private fun updateMessage(streamedMessage: Message) { private fun updateMessage(streamedMessage: Message) {
launchUI(strategy) { launchUI(strategy) {
val viewModelStreamedMessage = mapper.map(streamedMessage) val viewModelStreamedMessage = mapper.map(streamedMessage)
......
...@@ -2,8 +2,9 @@ package chat.rocket.android.chatroom.presentation ...@@ -2,8 +2,9 @@ package chat.rocket.android.chatroom.presentation
import android.net.Uri import android.net.Uri
import chat.rocket.android.chatroom.viewmodel.BaseViewModel import chat.rocket.android.chatroom.viewmodel.BaseViewModel
import chat.rocket.android.chatroom.viewmodel.ChatRoomViewModel import chat.rocket.android.chatroom.viewmodel.suggestion.ChatRoomSuggestionViewModel
import chat.rocket.android.chatroom.viewmodel.PeopleViewModel import chat.rocket.android.chatroom.viewmodel.suggestion.CommandSuggestionViewModel
import chat.rocket.android.chatroom.viewmodel.suggestion.PeopleSuggestionViewModel
import chat.rocket.android.core.behaviours.LoadingView import chat.rocket.android.core.behaviours.LoadingView
import chat.rocket.android.core.behaviours.MessageView import chat.rocket.android.core.behaviours.MessageView
import chat.rocket.core.internal.realtime.State import chat.rocket.core.internal.realtime.State
...@@ -102,12 +103,19 @@ interface ChatRoomView : LoadingView, MessageView { ...@@ -102,12 +103,19 @@ interface ChatRoomView : LoadingView, MessageView {
fun showInvalidFileSize(fileSize: Int, maxFileSize: Int) fun showInvalidFileSize(fileSize: Int, maxFileSize: Int)
fun showConnectionState(state: State) fun showConnectionState(state: State)
fun populateMembers(members: List<PeopleViewModel>) fun populatePeopleSuggestions(members: List<PeopleSuggestionViewModel>)
fun populateRooms(chatRooms: List<ChatRoomViewModel>) fun populateRoomSuggestions(chatRooms: List<ChatRoomSuggestionViewModel>)
/** /**
* This user has joined the chat callback. * This user has joined the chat callback.
*/ */
fun onJoined() fun onJoined()
fun showReactionsPopup(messageId: String) fun showReactionsPopup(messageId: String)
/**
* Show list of commands.
*
* @param commands The list of available commands.
*/
fun populateCommandSuggestions(commands: List<CommandSuggestionViewModel>)
} }
\ No newline at end of file
...@@ -15,16 +15,14 @@ import android.support.v7.widget.LinearLayoutManager ...@@ -15,16 +15,14 @@ import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView import android.support.v7.widget.RecyclerView
import android.view.* import android.view.*
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.chatroom.adapter.ChatRoomAdapter import chat.rocket.android.chatroom.adapter.*
import chat.rocket.android.chatroom.adapter.PEOPLE
import chat.rocket.android.chatroom.adapter.PeopleSuggestionsAdapter
import chat.rocket.android.chatroom.adapter.RoomSuggestionsAdapter
import chat.rocket.android.chatroom.presentation.ChatRoomPresenter import chat.rocket.android.chatroom.presentation.ChatRoomPresenter
import chat.rocket.android.chatroom.presentation.ChatRoomView import chat.rocket.android.chatroom.presentation.ChatRoomView
import chat.rocket.android.chatroom.viewmodel.BaseViewModel import chat.rocket.android.chatroom.viewmodel.BaseViewModel
import chat.rocket.android.chatroom.viewmodel.ChatRoomViewModel
import chat.rocket.android.chatroom.viewmodel.MessageViewModel import chat.rocket.android.chatroom.viewmodel.MessageViewModel
import chat.rocket.android.chatroom.viewmodel.PeopleViewModel import chat.rocket.android.chatroom.viewmodel.suggestion.ChatRoomSuggestionViewModel
import chat.rocket.android.chatroom.viewmodel.suggestion.CommandSuggestionViewModel
import chat.rocket.android.chatroom.viewmodel.suggestion.PeopleSuggestionViewModel
import chat.rocket.android.helper.EndlessRecyclerViewScrollListener import chat.rocket.android.helper.EndlessRecyclerViewScrollListener
import chat.rocket.android.helper.KeyboardHelper import chat.rocket.android.helper.KeyboardHelper
import chat.rocket.android.helper.MessageParser import chat.rocket.android.helper.MessageParser
...@@ -287,14 +285,18 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -287,14 +285,18 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error)) override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error))
override fun populateMembers(members: List<PeopleViewModel>) { override fun populatePeopleSuggestions(members: List<PeopleSuggestionViewModel>) {
suggestions_view.addItems("@", members) suggestions_view.addItems("@", members)
} }
override fun populateRooms(chatRooms: List<ChatRoomViewModel>) { override fun populateRoomSuggestions(chatRooms: List<ChatRoomSuggestionViewModel>) {
suggestions_view.addItems("#", chatRooms) suggestions_view.addItems("#", chatRooms)
} }
override fun populateCommandSuggestions(commands: List<CommandSuggestionViewModel>) {
suggestions_view.addItems("/", commands)
}
override fun copyToClipboard(message: String) { override fun copyToClipboard(message: String) {
activity?.apply { activity?.apply {
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
...@@ -494,6 +496,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -494,6 +496,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
private fun setupSuggestionsView() { private fun setupSuggestionsView() {
suggestions_view.anchor(text_message) suggestions_view.anchor(text_message)
.bindTokenAdapter(PeopleSuggestionsAdapter()) .bindTokenAdapter(PeopleSuggestionsAdapter())
.bindTokenAdapter(CommandSuggestionsAdapter())
.bindTokenAdapter(RoomSuggestionsAdapter()) .bindTokenAdapter(RoomSuggestionsAdapter())
.addSuggestionProviderAction("@") { query -> .addSuggestionProviderAction("@") { query ->
if (query.isNotEmpty()) { if (query.isNotEmpty()) {
...@@ -505,6 +508,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -505,6 +508,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
presenter.loadChatRooms() presenter.loadChatRooms()
} }
} }
.addSuggestionProviderAction("/") { query ->
presenter.loadCommands(query)
}
presenter.loadCommands()
} }
private fun openEmojiKeyboardPopup() { private fun openEmojiKeyboardPopup() {
......
package chat.rocket.android.chatroom.viewmodel package chat.rocket.android.chatroom.viewmodel.suggestion
import chat.rocket.android.widget.autocompletion.model.SuggestionModel import chat.rocket.android.widget.autocompletion.model.SuggestionModel
class ChatRoomViewModel(text: String, class ChatRoomSuggestionViewModel(text: String,
val fullName: String, val fullName: String,
val name: String, val name: String,
searchList: List<String>) : SuggestionModel(text, searchList, false) { searchList: List<String>) : SuggestionModel(text, searchList, false) {
} }
\ No newline at end of file
package chat.rocket.android.chatroom.viewmodel.suggestion
import chat.rocket.android.widget.autocompletion.model.SuggestionModel
class CommandSuggestionViewModel(text: String,
val description: String,
searchList: List<String>) : SuggestionModel(text, searchList)
\ No newline at end of file
package chat.rocket.android.chatroom.viewmodel package chat.rocket.android.chatroom.viewmodel.suggestion
import chat.rocket.android.widget.autocompletion.model.SuggestionModel import chat.rocket.android.widget.autocompletion.model.SuggestionModel
import chat.rocket.common.model.UserStatus import chat.rocket.common.model.UserStatus
class PeopleViewModel(val imageUri: String, class PeopleSuggestionViewModel(val imageUri: String,
text: String, text: String,
val username: String, val username: String,
val name: String, val name: String,
val status: UserStatus?, val status: UserStatus?,
pinned: Boolean = false, pinned: Boolean = false,
searchList: List<String>) : SuggestionModel(text, searchList, pinned) { searchList: List<String>) : SuggestionModel(text, searchList, pinned) {
override fun toString(): String { override fun toString(): String {
return "PeopleViewModel(imageUri='$imageUri', username='$username', name='$name', status=$status, pinned=$pinned)" return "PeopleSuggestionViewModel(imageUri='$imageUri', username='$username', name='$name', status=$status, pinned=$pinned)"
} }
} }
\ No newline at end of file
...@@ -114,7 +114,7 @@ class SuggestionsView : FrameLayout, TextWatcher { ...@@ -114,7 +114,7 @@ class SuggestionsView : FrameLayout, TextWatcher {
private fun swapAdapter(adapter: SuggestionsAdapter<*>): SuggestionsView { private fun swapAdapter(adapter: SuggestionsAdapter<*>): SuggestionsView {
recyclerView.adapter = adapter recyclerView.adapter = adapter
// Don't override if user set an item click listener already/ // Don't override if user has set an item click listener already
if (!adapter.hasItemClickListener()) { if (!adapter.hasItemClickListener()) {
setOnItemClickListener(adapter) { setOnItemClickListener(adapter) {
// set default item click behavior // set default item click behavior
...@@ -123,7 +123,7 @@ class SuggestionsView : FrameLayout, TextWatcher { ...@@ -123,7 +123,7 @@ class SuggestionsView : FrameLayout, TextWatcher {
return this return this
} }
fun getAdapterForToken(token: String): SuggestionsAdapter<*>? = adaptersByToken.get(token) private fun getAdapterForToken(token: String): SuggestionsAdapter<*>? = adaptersByToken.get(token)
fun anchor(editText: EditText): SuggestionsView { fun anchor(editText: EditText): SuggestionsView {
editText.removeTextChangedListener(this) editText.removeTextChangedListener(this)
......
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="2dp"
android:background="@color/suggestion_background_color"
android:orientation="horizontal">
<TextView
android:id="@+id/text_command_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_marginStart="16dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@color/black"
android:textSize="16sp"
tools:text="/leave" />
<TextView
android:id="@+id/text_command_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="16dp"
android:layout_toEndOf="@id/text_command_name"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@color/gray_material"
android:textSize="16sp"
tools:text="Leave a channel" />
</RelativeLayout>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment