Commit a9bcdc2a authored by Leonardo Aramaki's avatar Leonardo Aramaki

Merge branch 'develop' into fix/noop-onorderedlist

parents 8ccb7bf0 3b717de3
...@@ -108,7 +108,6 @@ dependencies { ...@@ -108,7 +108,6 @@ dependencies {
implementation libraries.timber implementation libraries.timber
implementation libraries.threeTenABP implementation libraries.threeTenABP
implementation libraries.rxBinding
implementation libraries.fresco implementation libraries.fresco
api libraries.frescoOkHttp api libraries.frescoOkHttp
......
...@@ -139,6 +139,11 @@ class ChatRoomAdapter( ...@@ -139,6 +139,11 @@ class ChatRoomAdapter(
} }
} }
fun clearData() {
dataSet.clear()
notifyDataSetChanged()
}
fun appendData(dataSet: List<BaseUiModel<*>>) { fun appendData(dataSet: List<BaseUiModel<*>>) {
val previousDataSetSize = this.dataSet.size val previousDataSetSize = this.dataSet.size
this.dataSet.addAll(dataSet) this.dataSet.addAll(dataSet)
......
package chat.rocket.android.chatroom.presentation package chat.rocket.android.chatroom.presentation
import android.graphics.BitmapFactory
import android.net.Uri import android.net.Uri
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.chatroom.adapter.AutoCompleteType import chat.rocket.android.chatroom.adapter.AutoCompleteType
...@@ -64,6 +63,7 @@ import chat.rocket.core.internal.rest.unstarMessage ...@@ -64,6 +63,7 @@ import chat.rocket.core.internal.rest.unstarMessage
import chat.rocket.core.internal.rest.updateMessage import chat.rocket.core.internal.rest.updateMessage
import chat.rocket.core.internal.rest.uploadFile import chat.rocket.core.internal.rest.uploadFile
import chat.rocket.core.internal.rest.favorite import chat.rocket.core.internal.rest.favorite
import chat.rocket.core.internal.rest.searchMessages
import chat.rocket.core.model.ChatRoomRole import chat.rocket.core.model.ChatRoomRole
import chat.rocket.core.model.Command import chat.rocket.core.model.Command
import chat.rocket.core.model.Message import chat.rocket.core.model.Message
...@@ -158,7 +158,12 @@ class ChatRoomPresenter @Inject constructor( ...@@ -158,7 +158,12 @@ class ChatRoomPresenter @Inject constructor(
} ?: false } ?: false
} }
fun loadMessages(chatRoomId: String, chatRoomType: String, offset: Long = 0) { fun loadMessages(
chatRoomId: String,
chatRoomType: String,
offset: Long = 0,
clearDataSet: Boolean = false
) {
this.chatRoomId = chatRoomId this.chatRoomId = chatRoomId
this.chatRoomType = chatRoomType this.chatRoomType = chatRoomType
launchUI(strategy) { launchUI(strategy) {
...@@ -173,13 +178,13 @@ class ChatRoomPresenter @Inject constructor( ...@@ -173,13 +178,13 @@ class ChatRoomPresenter @Inject constructor(
) )
) )
if (oldMessages.isNotEmpty()) { if (oldMessages.isNotEmpty()) {
view.showMessages(oldMessages) view.showMessages(oldMessages, clearDataSet)
loadMissingMessages() loadMissingMessages()
} else { } else {
loadAndShowMessages(chatRoomId, chatRoomType, offset) loadAndShowMessages(chatRoomId, chatRoomType, offset, clearDataSet)
} }
} else { } else {
loadAndShowMessages(chatRoomId, chatRoomType, offset) loadAndShowMessages(chatRoomId, chatRoomType, offset, clearDataSet)
} }
// TODO: For now we are marking the room as read if we can get the messages (I mean, no exception occurs) // TODO: For now we are marking the room as read if we can get the messages (I mean, no exception occurs)
...@@ -206,21 +211,49 @@ class ChatRoomPresenter @Inject constructor( ...@@ -206,21 +211,49 @@ class ChatRoomPresenter @Inject constructor(
private suspend fun loadAndShowMessages( private suspend fun loadAndShowMessages(
chatRoomId: String, chatRoomId: String,
chatRoomType: String, chatRoomType: String,
offset: Long = 0 offset: Long = 0,
clearDataSet: Boolean
) { ) {
val messages = val messages =
retryIO(description = "messages chatRoom: $chatRoomId, type: $chatRoomType, offset: $offset") { retryIO("loadAndShowMessages($chatRoomId, $chatRoomType, $offset") {
client.messages(chatRoomId, roomTypeOf(chatRoomType), offset, 30).result client.messages(chatRoomId, roomTypeOf(chatRoomType), offset, 30).result
} }
messagesRepository.saveAll(messages) messagesRepository.saveAll(messages)
view.showMessages( view.showMessages(
mapper.map(messages, RoomUiModel( mapper.map(
roles = chatRoles, messages,
isBroadcast = chatIsBroadcast, isRoom = true RoomUiModel(roles = chatRoles, isBroadcast = chatIsBroadcast, isRoom = true)
)) ),
clearDataSet
) )
} }
fun searchMessages(chatRoomId: String, searchText: String) {
launchUI(strategy) {
try {
view.showLoading()
val messages = retryIO("searchMessages($chatRoomId, $searchText)") {
client.searchMessages(chatRoomId, searchText).result
}
view.showSearchedMessages(
mapper.map(
messages,
RoomUiModel(chatRoles, chatIsBroadcast, true)
)
)
} catch (ex: Exception) {
Timber.e(ex)
ex.message?.let {
view.showMessage(it)
}.ifNull {
view.showGenericErrorMessage()
}
} finally {
view.hideLoading()
}
}
}
fun sendMessage(chatRoomId: String, text: String, messageId: String?) { fun sendMessage(chatRoomId: String, text: String, messageId: String?) {
launchUI(strategy) { launchUI(strategy) {
try { try {
......
package chat.rocket.android.chatroom.presentation package chat.rocket.android.chatroom.presentation
import android.net.Uri
import chat.rocket.android.chatroom.uimodel.BaseUiModel import chat.rocket.android.chatroom.uimodel.BaseUiModel
import chat.rocket.android.chatroom.uimodel.suggestion.ChatRoomSuggestionUiModel import chat.rocket.android.chatroom.uimodel.suggestion.ChatRoomSuggestionUiModel
import chat.rocket.android.chatroom.uimodel.suggestion.CommandSuggestionUiModel import chat.rocket.android.chatroom.uimodel.suggestion.CommandSuggestionUiModel
...@@ -23,8 +22,16 @@ interface ChatRoomView : LoadingView, MessageView { ...@@ -23,8 +22,16 @@ interface ChatRoomView : LoadingView, MessageView {
* Shows the chat room messages. * Shows the chat room messages.
* *
* @param dataSet The data set to show. * @param dataSet The data set to show.
* @param clearDataSet If true it will clear the previous data set.
*/ */
fun showMessages(dataSet: List<BaseUiModel<*>>) fun showMessages(dataSet: List<BaseUiModel<*>>, clearDataSet: Boolean)
/**
* Shows the chat room messages in the basis of a search term.
*
* @param dataSet The data set to show.
*/
fun showSearchedMessages(dataSet: List<BaseUiModel<*>>)
/** /**
* Send a message to a chat room. * Send a message to a chat room.
......
...@@ -55,7 +55,7 @@ import chat.rocket.android.helper.EndlessRecyclerViewScrollListener ...@@ -55,7 +55,7 @@ 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
import chat.rocket.android.helper.ImageHelper import chat.rocket.android.helper.ImageHelper
import chat.rocket.android.util.extensions.asObservable import chat.rocket.android.util.extension.asObservable
import chat.rocket.android.util.extensions.circularRevealOrUnreveal import chat.rocket.android.util.extensions.circularRevealOrUnreveal
import chat.rocket.android.util.extensions.fadeIn import chat.rocket.android.util.extensions.fadeIn
import chat.rocket.android.util.extensions.fadeOut import chat.rocket.android.util.extensions.fadeOut
...@@ -119,12 +119,12 @@ private const val BUNDLE_CHAT_ROOM_IS_CREATOR = "chat_room_is_creator" ...@@ -119,12 +119,12 @@ private const val BUNDLE_CHAT_ROOM_IS_CREATOR = "chat_room_is_creator"
private const val BUNDLE_CHAT_ROOM_IS_FAVORITE = "chat_room_is_favorite" private const val BUNDLE_CHAT_ROOM_IS_FAVORITE = "chat_room_is_favorite"
private const val BUNDLE_CHAT_ROOM_MESSAGE = "chat_room_message" private const val BUNDLE_CHAT_ROOM_MESSAGE = "chat_room_message"
private const val MENU_ACTION_FAVORITE_UNFAVORITE_CHAT = 1 internal const val MENU_ACTION_FAVORITE_UNFAVORITE_CHAT = 1
private const val MENU_ACTION_MEMBER = 2 internal const val MENU_ACTION_MEMBER = 2
private const val MENU_ACTION_MENTIONS = 3 internal const val MENU_ACTION_MENTIONS = 3
private const val MENU_ACTION_PINNED_MESSAGES = 4 internal const val MENU_ACTION_PINNED_MESSAGES = 4
private const val MENU_ACTION_FAVORITE_MESSAGES = 5 internal const val MENU_ACTION_FAVORITE_MESSAGES = 5
private const val MENU_ACTION_FILES = 6 internal const val MENU_ACTION_FILES = 6
class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiReactionListener { class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiReactionListener {
@Inject @Inject
...@@ -134,13 +134,13 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -134,13 +134,13 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
private lateinit var adapter: ChatRoomAdapter private lateinit var adapter: ChatRoomAdapter
internal lateinit var chatRoomId: String internal lateinit var chatRoomId: String
private lateinit var chatRoomName: String private lateinit var chatRoomName: String
private lateinit var chatRoomType: String internal lateinit var chatRoomType: String
private var newMessageCount: Int = 0 private var newMessageCount: Int = 0
private var chatRoomMessage: String? = null private var chatRoomMessage: String? = null
private var isSubscribed: Boolean = true private var isSubscribed: Boolean = true
private var isReadOnly: Boolean = false private var isReadOnly: Boolean = false
private var isCreator: Boolean = false private var isCreator: Boolean = false
private var isFavorite: Boolean = false internal var isFavorite: Boolean = false
private var isBroadcastChannel: Boolean = false private var isBroadcastChannel: Boolean = false
private lateinit var emojiKeyboardPopup: EmojiKeyboardPopup private lateinit var emojiKeyboardPopup: EmojiKeyboardPopup
private var chatRoomLastSeen: Long = -1 private var chatRoomLastSeen: Long = -1
...@@ -151,6 +151,8 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -151,6 +151,8 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
private val compositeDisposable = CompositeDisposable() private val compositeDisposable = CompositeDisposable()
private var playComposeMessageButtonsAnimation = true private var playComposeMessageButtonsAnimation = true
internal var isSearchTermQueried = false
// For reveal and unreveal anim. // For reveal and unreveal anim.
private val hypotenuse by lazy { private val hypotenuse by lazy {
Math.hypot( Math.hypot(
...@@ -253,87 +255,22 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -253,87 +255,22 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
if (resultData != null && resultCode == Activity.RESULT_OK) { if (resultData != null && resultCode == Activity.RESULT_OK) {
when (requestCode) { when (requestCode) {
REQUEST_CODE_FOR_PERFORM_SAF -> { REQUEST_CODE_FOR_PERFORM_SAF -> showFileAttachmentDialog(resultData.data)
showFileAttachmentDialog(resultData.data) REQUEST_CODE_FOR_DRAW -> showDrawAttachmentDialog(
} resultData.getByteArrayExtra(DRAWING_BYTE_ARRAY_EXTRA_DATA)
REQUEST_CODE_FOR_DRAW -> { )
showDrawAttachmentDialog(
resultData.getByteArrayExtra(DRAWING_BYTE_ARRAY_EXTRA_DATA)
)
}
} }
} }
} }
override fun onPrepareOptionsMenu(menu: Menu) { override fun onPrepareOptionsMenu(menu: Menu) {
menu.clear() menu.clear()
if (isFavorite) { setupMenu(menu)
menu.add(
Menu.NONE,
MENU_ACTION_FAVORITE_UNFAVORITE_CHAT,
Menu.NONE,
R.string.title_unfavorite_chat
)
.setIcon(R.drawable.ic_star_yellow_24dp)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
} else {
menu.add(
Menu.NONE,
MENU_ACTION_FAVORITE_UNFAVORITE_CHAT,
Menu.NONE,
R.string.title_favorite_chat
)
.setIcon(R.drawable.ic_star_border_white_24dp)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
}
menu.add(
Menu.NONE,
MENU_ACTION_MEMBER,
Menu.NONE,
R.string.title_members_list
)
menu.add(
Menu.NONE,
MENU_ACTION_MENTIONS,
Menu.NONE,
R.string.msg_mentions
)
menu.add(
Menu.NONE,
MENU_ACTION_PINNED_MESSAGES,
Menu.NONE,
R.string.title_pinned_messages
)
menu.add(
Menu.NONE,
MENU_ACTION_FAVORITE_MESSAGES,
Menu.NONE,
R.string.title_favorite_messages
)
menu.add(
Menu.NONE,
MENU_ACTION_FILES,
Menu.NONE,
R.string.title_files
)
super.onPrepareOptionsMenu(menu) super.onPrepareOptionsMenu(menu)
} }
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) { setOnMenuItemClickListener(item)
MENU_ACTION_FAVORITE_UNFAVORITE_CHAT -> {
presenter.toggleFavoriteChatRoom(chatRoomId, isFavorite)
}
MENU_ACTION_MEMBER -> presenter.toMembersList(chatRoomId)
MENU_ACTION_MENTIONS -> presenter.toMentions(chatRoomId)
MENU_ACTION_PINNED_MESSAGES -> presenter.toPinnedMessageList(chatRoomId)
MENU_ACTION_FAVORITE_MESSAGES -> presenter.toFavoriteMessageList(chatRoomId)
MENU_ACTION_FILES -> presenter.toFileList(chatRoomId)
}
return true return true
} }
...@@ -342,8 +279,12 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -342,8 +279,12 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
activity?.invalidateOptionsMenu() activity?.invalidateOptionsMenu()
} }
override fun showMessages(dataSet: List<BaseUiModel<*>>) { override fun showMessages(dataSet: List<BaseUiModel<*>>, clearDataSet: Boolean) {
ui { ui {
if (clearDataSet) {
adapter.clearData()
}
// track the message sent immediately after the current message // track the message sent immediately after the current message
var prevMessageUiModel: MessageUiModel? = null var prevMessageUiModel: MessageUiModel? = null
...@@ -392,6 +333,13 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -392,6 +333,13 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
} }
} }
override fun showSearchedMessages(dataSet: List<BaseUiModel<*>>) {
recycler_view.removeOnScrollListener(endlessRecyclerViewScrollListener)
adapter.clearData()
adapter.prependData(dataSet)
empty_chat_view.isVisible = adapter.itemCount == 0
}
override fun onRoomUpdated( override fun onRoomUpdated(
userCanPost: Boolean, userCanPost: Boolean,
channelIsBroadcast: Boolean, channelIsBroadcast: Boolean,
...@@ -986,4 +934,4 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -986,4 +934,4 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
private fun setupToolbar(toolbarTitle: String) { private fun setupToolbar(toolbarTitle: String) {
(activity as ChatRoomActivity).showToolbarTitle(toolbarTitle) (activity as ChatRoomActivity).showToolbarTitle(toolbarTitle)
} }
} }
\ No newline at end of file
package chat.rocket.android.chatroom.ui
import android.content.Context
import android.view.Menu
import android.view.MenuItem
import android.widget.EditText
import androidx.appcompat.widget.SearchView
import androidx.core.content.res.ResourcesCompat
import chat.rocket.android.R
import chat.rocket.android.util.extension.onQueryTextListener
import chat.rocket.common.model.RoomType
internal fun ChatRoomFragment.setupMenu(menu: Menu) {
setupSearchMessageMenuItem(menu, requireContext())
setupFavoriteMenuItem(menu)
if (chatRoomType != RoomType.DIRECT_MESSAGE) {
menu.add(
Menu.NONE,
MENU_ACTION_MEMBER,
Menu.NONE,
R.string.title_members_list
)
menu.add(
Menu.NONE,
MENU_ACTION_MENTIONS,
Menu.NONE,
R.string.msg_mentions
)
}
menu.add(
Menu.NONE,
MENU_ACTION_PINNED_MESSAGES,
Menu.NONE,
R.string.title_pinned_messages
)
menu.add(
Menu.NONE,
MENU_ACTION_FAVORITE_MESSAGES,
Menu.NONE,
R.string.title_favorite_messages
)
menu.add(
Menu.NONE,
MENU_ACTION_FILES,
Menu.NONE,
R.string.title_files
)
}
internal fun ChatRoomFragment.setOnMenuItemClickListener(item: MenuItem) {
when (item.itemId) {
MENU_ACTION_FAVORITE_UNFAVORITE_CHAT -> presenter.toggleFavoriteChatRoom(
chatRoomId,
isFavorite
)
MENU_ACTION_MEMBER -> presenter.toMembersList(chatRoomId)
MENU_ACTION_MENTIONS -> presenter.toMentions(chatRoomId)
MENU_ACTION_PINNED_MESSAGES -> presenter.toPinnedMessageList(chatRoomId)
MENU_ACTION_FAVORITE_MESSAGES -> presenter.toFavoriteMessageList(chatRoomId)
MENU_ACTION_FILES -> presenter.toFileList(chatRoomId)
}
}
private fun ChatRoomFragment.setupSearchMessageMenuItem(menu: Menu, context: Context) {
val searchItem = menu.add(
Menu.NONE,
Menu.NONE,
Menu.NONE,
R.string.title_search_message
).setActionView(SearchView(context))
.setIcon(R.drawable.ic_search_white_24dp)
.setShowAsActionFlags(
MenuItem.SHOW_AS_ACTION_IF_ROOM or MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW
)
(searchItem?.actionView as? SearchView)?.let {
// TODO: Check why we need to stylize the search text programmatically instead of by defining it in the styles.xml (ChatRoom.SearchView)
stylizeSearchView(it, context)
setupSearchViewTextListener(it)
if (it.isIconified) {
isSearchTermQueried = false
}
}
}
private fun stylizeSearchView(searchView: SearchView, context: Context) {
val searchText = searchView.findViewById<EditText>(androidx.appcompat.R.id.search_src_text)
searchText.setTextColor(ResourcesCompat.getColor(context.resources, R.color.color_white, null))
searchText.setHintTextColor(
ResourcesCompat.getColor(context.resources, R.color.color_white, null)
)
}
private fun ChatRoomFragment.setupSearchViewTextListener(searchView: SearchView) {
searchView.onQueryTextListener {
// TODO: We use isSearchTermQueried to avoid querying when the search view is expanded but the user doesn't start typing. Check for a native solution.
if (it.isEmpty() && isSearchTermQueried) {
presenter.loadMessages(chatRoomId, chatRoomType, clearDataSet = true)
} else if (it.isNotEmpty()){
presenter.searchMessages(chatRoomId, it)
isSearchTermQueried = true
}
}
}
private fun ChatRoomFragment.setupFavoriteMenuItem(menu: Menu) {
if (isFavorite) {
menu.add(
Menu.NONE,
MENU_ACTION_FAVORITE_UNFAVORITE_CHAT,
Menu.NONE,
R.string.title_unfavorite_chat
).setIcon(R.drawable.ic_star_yellow_24dp)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
} else {
menu.add(
Menu.NONE,
MENU_ACTION_FAVORITE_UNFAVORITE_CHAT,
Menu.NONE,
R.string.title_favorite_chat
).setIcon(R.drawable.ic_star_border_white_24dp)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
}
}
\ No newline at end of file
...@@ -46,15 +46,19 @@ class ChatRoomsFragmentModule { ...@@ -46,15 +46,19 @@ class ChatRoomsFragmentModule {
@Provides @Provides
@PerFragment @PerFragment
fun provideRocketChatClient(factory: RocketChatClientFactory, fun provideRocketChatClient(
@Named("currentServer") currentServer: String): RocketChatClient { factory: RocketChatClientFactory,
@Named("currentServer") currentServer: String
): RocketChatClient {
return factory.create(currentServer) return factory.create(currentServer)
} }
@Provides @Provides
@PerFragment @PerFragment
fun provideDatabaseManager(factory: DatabaseManagerFactory, fun provideDatabaseManager(
@Named("currentServer") currentServer: String): DatabaseManager { factory: DatabaseManagerFactory,
@Named("currentServer") currentServer: String
): DatabaseManager {
return factory.create(currentServer) return factory.create(currentServer)
} }
...@@ -64,31 +68,39 @@ class ChatRoomsFragmentModule { ...@@ -64,31 +68,39 @@ class ChatRoomsFragmentModule {
@Provides @Provides
@PerFragment @PerFragment
fun provideConnectionManager(factory: ConnectionManagerFactory, fun provideConnectionManager(
@Named("currentServer") currentServer: String): ConnectionManager { factory: ConnectionManagerFactory,
@Named("currentServer") currentServer: String
): ConnectionManager {
return factory.create(currentServer) return factory.create(currentServer)
} }
@Provides @Provides
@PerFragment @PerFragment
fun provideFetchChatRoomsInteractor(client: RocketChatClient, fun provideFetchChatRoomsInteractor(
dbManager: DatabaseManager): FetchChatRoomsInteractor { client: RocketChatClient,
dbManager: DatabaseManager
): FetchChatRoomsInteractor {
return FetchChatRoomsInteractor(client, dbManager) return FetchChatRoomsInteractor(client, dbManager)
} }
@Provides @Provides
@PerFragment @PerFragment
fun providePublicSettings(repository: SettingsRepository, fun providePublicSettings(
@Named("currentServer") currentServer: String): PublicSettings { repository: SettingsRepository,
@Named("currentServer") currentServer: String
): PublicSettings {
return repository.get(currentServer) return repository.get(currentServer)
} }
@Provides @Provides
@PerFragment @PerFragment
fun provideRoomMapper(context: Application, fun provideRoomMapper(
repository: SettingsRepository, context: Application,
localRepository: LocalRepository, repository: SettingsRepository,
@Named("currentServer") serverUrl: String): RoomUiModelMapper { localRepository: LocalRepository,
@Named("currentServer") serverUrl: String
): RoomUiModelMapper {
return RoomUiModelMapper(context, repository.get(serverUrl), localRepository, serverUrl) return RoomUiModelMapper(context, repository.get(serverUrl), localRepository, serverUrl)
} }
} }
\ No newline at end of file
...@@ -32,6 +32,7 @@ import chat.rocket.android.db.DatabaseManager ...@@ -32,6 +32,7 @@ import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.helper.ChatRoomsSortOrder import chat.rocket.android.helper.ChatRoomsSortOrder
import chat.rocket.android.helper.Constants import chat.rocket.android.helper.Constants
import chat.rocket.android.helper.SharedPreferenceHelper import chat.rocket.android.helper.SharedPreferenceHelper
import chat.rocket.android.util.extension.onQueryTextListener
import chat.rocket.android.util.extensions.fadeIn import chat.rocket.android.util.extensions.fadeIn
import chat.rocket.android.util.extensions.fadeOut import chat.rocket.android.util.extensions.fadeOut
import chat.rocket.android.util.extensions.inflate import chat.rocket.android.util.extensions.inflate
...@@ -164,15 +165,7 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView { ...@@ -164,15 +165,7 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
searchView = searchItem?.actionView as? SearchView searchView = searchItem?.actionView as? SearchView
searchView?.setIconifiedByDefault(false) searchView?.setIconifiedByDefault(false)
searchView?.maxWidth = Integer.MAX_VALUE searchView?.maxWidth = Integer.MAX_VALUE
searchView?.setOnQueryTextListener(object : SearchView.OnQueryTextListener { searchView?.onQueryTextListener { queryChatRoomsByName(it) }
override fun onQueryTextSubmit(query: String?): Boolean {
return queryChatRoomsByName(query)
}
override fun onQueryTextChange(newText: String?): Boolean {
return queryChatRoomsByName(newText)
}
})
val expandListener = object : MenuItem.OnActionExpandListener { val expandListener = object : MenuItem.OnActionExpandListener {
override fun onMenuItemActionCollapse(item: MenuItem): Boolean { override fun onMenuItemActionCollapse(item: MenuItem): Boolean {
......
...@@ -20,7 +20,7 @@ import chat.rocket.android.createchannel.presentation.CreateChannelView ...@@ -20,7 +20,7 @@ import chat.rocket.android.createchannel.presentation.CreateChannelView
import chat.rocket.android.main.ui.MainActivity import chat.rocket.android.main.ui.MainActivity
import chat.rocket.android.members.adapter.MembersAdapter import chat.rocket.android.members.adapter.MembersAdapter
import chat.rocket.android.members.uimodel.MemberUiModel import chat.rocket.android.members.uimodel.MemberUiModel
import chat.rocket.android.util.extensions.asObservable import chat.rocket.android.util.extension.asObservable
import chat.rocket.android.util.extensions.inflate import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.showToast import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.ui import chat.rocket.android.util.extensions.ui
...@@ -221,7 +221,6 @@ class CreateChannelFragment : Fragment(), CreateChannelView, ActionMode.Callback ...@@ -221,7 +221,6 @@ class CreateChannelFragment : Fragment(), CreateChannelView, ActionMode.Callback
LinearLayoutManager(context, RecyclerView.VERTICAL, false) LinearLayoutManager(context, RecyclerView.VERTICAL, false)
recycler_view.addItemDecoration(DividerItemDecoration(it, DividerItemDecoration.HORIZONTAL)) recycler_view.addItemDecoration(DividerItemDecoration(it, DividerItemDecoration.HORIZONTAL))
recycler_view.adapter = adapter recycler_view.adapter = adapter
} }
} }
......
...@@ -38,20 +38,20 @@ import timber.log.Timber ...@@ -38,20 +38,20 @@ import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
class MainPresenter @Inject constructor( class MainPresenter @Inject constructor(
private val view: MainView, private val view: MainView,
private val strategy: CancelStrategy, private val strategy: CancelStrategy,
private val navigator: MainNavigator, private val navigator: MainNavigator,
private val tokenRepository: TokenRepository, private val tokenRepository: TokenRepository,
private val serverInteractor: GetCurrentServerInteractor, private val serverInteractor: GetCurrentServerInteractor,
private val localRepository: LocalRepository, private val localRepository: LocalRepository,
private val navHeaderMapper: NavHeaderUiModelMapper, private val navHeaderMapper: NavHeaderUiModelMapper,
private val saveAccountInteractor: SaveAccountInteractor, private val saveAccountInteractor: SaveAccountInteractor,
private val getAccountsInteractor: GetAccountsInteractor, private val getAccountsInteractor: GetAccountsInteractor,
private val removeAccountInteractor: RemoveAccountInteractor, private val removeAccountInteractor: RemoveAccountInteractor,
private val factory: RocketChatClientFactory, private val factory: RocketChatClientFactory,
dbManagerFactory: DatabaseManagerFactory, dbManagerFactory: DatabaseManagerFactory,
getSettingsInteractor: GetSettingsInteractor, getSettingsInteractor: GetSettingsInteractor,
managerFactory: ConnectionManagerFactory managerFactory: ConnectionManagerFactory
) : CheckServerPresenter(strategy, factory, view = view) { ) : CheckServerPresenter(strategy, factory, view = view) {
private val currentServer = serverInteractor.get()!! private val currentServer = serverInteractor.get()!!
private val manager = managerFactory.create(currentServer) private val manager = managerFactory.create(currentServer)
...@@ -69,16 +69,34 @@ class MainPresenter @Inject constructor( ...@@ -69,16 +69,34 @@ class MainPresenter @Inject constructor(
fun toCreateChannel() = navigator.toCreateChannel() fun toCreateChannel() = navigator.toCreateChannel()
fun loadServerAccounts() {
launchUI(strategy) {
try {
view.setupServerAccountList(getAccountsInteractor.get())
} catch (ex: Exception) {
when (ex) {
is RocketChatAuthException -> logout()
else -> {
Timber.d(ex, "Error loading serve accounts")
ex.message?.let {
view.showMessage(it)
}.ifNull {
view.showGenericErrorMessage()
}
}
}
}
}
}
fun loadCurrentInfo() { fun loadCurrentInfo() {
checkServerInfo(currentServer) checkServerInfo(currentServer)
launchUI(strategy) { launchUI(strategy) {
try { try {
val me = retryIO("me") { val me = retryIO("me") { client.me() }
client.me()
}
val model = navHeaderMapper.mapToUiModel(me) val model = navHeaderMapper.mapToUiModel(me)
saveAccount(model) saveAccount(model)
view.setupNavHeader(model, getAccountsInteractor.get()) view.setupUserAccountInfo(model)
} catch (ex: Exception) { } catch (ex: Exception) {
when (ex) { when (ex) {
is RocketChatAuthException -> { is RocketChatAuthException -> {
...@@ -208,8 +226,6 @@ class MainPresenter @Inject constructor( ...@@ -208,8 +226,6 @@ class MainPresenter @Inject constructor(
} }
} }
private suspend fun updateMyself(myself: Myself) { private fun updateMyself(myself: Myself) =
val model = navHeaderMapper.mapToUiModel(myself) view.setupUserAccountInfo(navHeaderMapper.mapToUiModel(myself))
view.setupNavHeader(model, getAccountsInteractor.get())
}
} }
\ No newline at end of file
...@@ -16,17 +16,24 @@ interface MainView : MessageView, VersionCheckView { ...@@ -16,17 +16,24 @@ interface MainView : MessageView, VersionCheckView {
fun showUserStatus(userStatus: UserStatus) fun showUserStatus(userStatus: UserStatus)
/** /**
* Setups the navigation header. * Setups the user account info (displayed in the nav. header)
* *
* @param uiModel The [NavHeaderUiModel]. * @param uiModel The [NavHeaderUiModel].
* @param accounts The list of accounts.
*/ */
fun setupNavHeader(uiModel: NavHeaderUiModel, accounts: List<Account>) fun setupUserAccountInfo(uiModel: NavHeaderUiModel)
/**
* Setups the server account list.
*
* @param serverAccountList The list of server accounts.
*/
fun setupServerAccountList(serverAccountList: List<Account>)
fun closeServerSelection() fun closeServerSelection()
fun invalidateToken(token: String) fun invalidateToken(token: String)
fun showProgress() fun showProgress()
fun hideProgress() fun hideProgress()
} }
\ No newline at end of file
...@@ -10,7 +10,6 @@ import androidx.appcompat.app.AppCompatActivity ...@@ -10,7 +10,6 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import android.view.Gravity import android.view.Gravity
import android.view.MenuItem import android.view.MenuItem
import android.view.View
import androidx.annotation.IdRes import androidx.annotation.IdRes
import androidx.drawerlayout.widget.DrawerLayout import androidx.drawerlayout.widget.DrawerLayout
import chat.rocket.android.BuildConfig import chat.rocket.android.BuildConfig
...@@ -56,6 +55,7 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, ...@@ -56,6 +55,7 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
private var expanded = false private var expanded = false
private val headerLayout by lazy { view_navigation.getHeaderView(0) } private val headerLayout by lazy { view_navigation.getHeaderView(0) }
private var chatRoomId: String? = null private var chatRoomId: String? = null
private var progressDialog : ProgressDialog? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this) AndroidInjection.inject(this)
...@@ -75,6 +75,7 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, ...@@ -75,6 +75,7 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
chatRoomId = intent.getStringExtra(INTENT_CHAT_ROOM_ID) chatRoomId = intent.getStringExtra(INTENT_CHAT_ROOM_ID)
presenter.connect() presenter.connect()
presenter.loadServerAccounts()
presenter.loadCurrentInfo() presenter.loadCurrentInfo()
setupToolbar() setupToolbar()
setupNavigationView() setupNavigationView()
...@@ -119,8 +120,7 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, ...@@ -119,8 +120,7 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
} }
} }
override fun setupNavHeader(uiModel: NavHeaderUiModel, accounts: List<Account>) { override fun setupUserAccountInfo(uiModel: NavHeaderUiModel) {
Timber.d("Setting up nav header: $uiModel")
with(headerLayout) { with(headerLayout) {
with(uiModel) { with(uiModel) {
if (userStatus != null) { if (userStatus != null) {
...@@ -139,10 +139,43 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, ...@@ -139,10 +139,43 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
} }
text_server_url.text = uiModel.serverUrl text_server_url.text = uiModel.serverUrl
} }
setupAccountsList(headerLayout, accounts)
} }
} }
override fun setupServerAccountList(serverAccountList: List<Account>) {
accounts_list.layoutManager = LinearLayoutManager(this)
accounts_list.adapter = AccountsAdapter(serverAccountList, object : Selector {
override fun onStatusSelected(userStatus: UserStatus) {
presenter.changeDefaultStatus(userStatus)
}
override fun onAccountSelected(serverUrl: String) {
presenter.changeServer(serverUrl)
}
override fun onAddedAccountSelected() {
presenter.addNewServer()
}
})
headerLayout.account_container.setOnClickListener {
it.image_account_expand.rotateBy(180f)
if (expanded) {
accounts_list.fadeOut()
} else {
accounts_list.fadeIn()
}
expanded = !expanded
}
headerLayout.image_avatar.setOnClickListener {
view_navigation.menu.findItem(R.id.action_update_profile).isChecked = true
presenter.toUserProfile()
drawer_layout.closeDrawer(Gravity.START)
}
}
override fun closeServerSelection() { override fun closeServerSelection() {
view_navigation.getHeaderView(0).account_container.performClick() view_navigation.getHeaderView(0).account_container.performClick()
} }
...@@ -174,9 +207,8 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, ...@@ -174,9 +207,8 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
.show() .show()
} }
override fun invalidateToken(token: String) { override fun invalidateToken(token: String) =
FirebaseInstanceId.getInstance().deleteToken(token, FirebaseMessaging.INSTANCE_ID_SCOPE) FirebaseInstanceId.getInstance().deleteToken(token, FirebaseMessaging.INSTANCE_ID_SCOPE)
}
override fun showMessage(resId: Int) = showToast(resId) override fun showMessage(resId: Int) = showToast(resId)
...@@ -221,57 +253,14 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, ...@@ -221,57 +253,14 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
} }
} }
private fun setupAccountsList(header: View, accounts: List<Account>) { fun getDrawerLayout(): DrawerLayout = drawer_layout
accounts_list.layoutManager = LinearLayoutManager(this)
accounts_list.adapter = AccountsAdapter(accounts, object : Selector {
override fun onStatusSelected(userStatus: UserStatus) {
presenter.changeDefaultStatus(userStatus)
}
override fun onAccountSelected(serverUrl: String) {
presenter.changeServer(serverUrl)
}
override fun onAddedAccountSelected() {
presenter.addNewServer()
}
})
header.account_container.setOnClickListener {
header.image_account_expand.rotateBy(180f)
if (expanded) {
accounts_list.fadeOut()
} else {
accounts_list.fadeIn()
}
expanded = !expanded
}
header.image_avatar.setOnClickListener {
view_navigation.menu.findItem(R.id.action_update_profile).isChecked = true
presenter.toUserProfile()
drawer_layout.closeDrawer(Gravity.START)
}
}
fun getDrawerLayout(): DrawerLayout {
return drawer_layout
}
fun openDrawer() { fun openDrawer() = drawer_layout.openDrawer(Gravity.START)
drawer_layout.openDrawer(Gravity.START)
}
fun closeDrawer() { fun closeDrawer() = drawer_layout.closeDrawer(Gravity.START)
drawer_layout.closeDrawer(Gravity.START)
}
fun setCheckedNavDrawerItem(@IdRes item: Int) { fun setCheckedNavDrawerItem(@IdRes item: Int) = view_navigation.setCheckedItem(item)
view_navigation.setCheckedItem(item)
}
private var progressDialog : ProgressDialog? = null
override fun showProgress() { override fun showProgress() {
progressDialog = ProgressDialog.show(this, getString(R.string.app_name), getString(R.string.msg_log_out), true, false) progressDialog = ProgressDialog.show(this, getString(R.string.app_name), getString(R.string.msg_log_out), true, false)
} }
......
...@@ -11,6 +11,7 @@ import chat.rocket.android.R ...@@ -11,6 +11,7 @@ import chat.rocket.android.R
import chat.rocket.android.main.ui.MainActivity import chat.rocket.android.main.ui.MainActivity
import chat.rocket.android.profile.presentation.ProfilePresenter import chat.rocket.android.profile.presentation.ProfilePresenter
import chat.rocket.android.profile.presentation.ProfileView import chat.rocket.android.profile.presentation.ProfileView
import chat.rocket.android.util.extension.asObservable
import chat.rocket.android.util.extensions.* import chat.rocket.android.util.extensions.*
import dagger.android.support.AndroidSupportInjection import dagger.android.support.AndroidSupportInjection
import io.reactivex.disposables.Disposable import io.reactivex.disposables.Disposable
......
...@@ -9,7 +9,7 @@ import chat.rocket.android.settings.password.presentation.PasswordPresenter ...@@ -9,7 +9,7 @@ import chat.rocket.android.settings.password.presentation.PasswordPresenter
import chat.rocket.android.settings.password.presentation.PasswordView import chat.rocket.android.settings.password.presentation.PasswordView
import chat.rocket.android.util.extensions.inflate import chat.rocket.android.util.extensions.inflate
import androidx.appcompat.view.ActionMode import androidx.appcompat.view.ActionMode
import chat.rocket.android.util.extensions.asObservable import chat.rocket.android.util.extension.asObservable
import chat.rocket.android.util.extensions.textContent import chat.rocket.android.util.extensions.textContent
import chat.rocket.android.util.extensions.ui import chat.rocket.android.util.extensions.ui
import dagger.android.support.AndroidSupportInjection import dagger.android.support.AndroidSupportInjection
......
...@@ -11,7 +11,6 @@ import kotlinx.coroutines.experimental.launch ...@@ -11,7 +11,6 @@ import kotlinx.coroutines.experimental.launch
import kotlinx.coroutines.experimental.withContext import kotlinx.coroutines.experimental.withContext
import kotlin.coroutines.experimental.CoroutineContext import kotlin.coroutines.experimental.CoroutineContext
class WrappedLiveData<Source, Output>( class WrappedLiveData<Source, Output>(
private val runContext: CoroutineContext = CommonPool, private val runContext: CoroutineContext = CommonPool,
private val source: LiveData<Source>, private val source: LiveData<Source>,
......
...@@ -2,9 +2,10 @@ ...@@ -2,9 +2,10 @@
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:autoMirrored="true" android:autoMirrored="true"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:viewportWidth="24.0"> android:viewportHeight="24.0">
<path <path
android:fillColor="#FFFFFF" android:fillColor="#FFFFFF"
android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z" /> android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z" />
</vector> </vector>
\ No newline at end of file
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<item <item
android:id="@+id/action_search" android:id="@+id/action_search"
android:icon="@drawable/ic_search_white_24px" android:icon="@drawable/ic_search_white_24dp"
android:title="@string/action_search" android:title="@string/action_search"
app:actionViewClass="androidx.appcompat.widget.SearchView" app:actionViewClass="androidx.appcompat.widget.SearchView"
app:showAsAction="ifRoom|collapseActionView" /> app:showAsAction="ifRoom|collapseActionView" />
......
...@@ -191,6 +191,10 @@ ...@@ -191,6 +191,10 @@
// TODO: Add proper translation. // TODO: Add proper translation.
<string name="permission_starring_not_allowed">Starring is not allowed</string> <string name="permission_starring_not_allowed">Starring is not allowed</string>
<!-- Search message -->
<!-- TODO Add proper translation-->
<string name="title_search_message">Search message</string>
<!-- Favorite/Unfavorite chat room --> <!-- Favorite/Unfavorite chat room -->
<!-- TODO Add proper translation--> <!-- TODO Add proper translation-->
<string name="title_favorite_chat">Favorite chat</string> <string name="title_favorite_chat">Favorite chat</string>
...@@ -285,5 +289,5 @@ ...@@ -285,5 +289,5 @@
<string name="notif_action_reply_hint">RESPUESTA</string> <string name="notif_action_reply_hint">RESPUESTA</string>
<string name="notif_error_sending">La respuesta ha fallado. Inténtalo de nuevo.</string> <string name="notif_error_sending">La respuesta ha fallado. Inténtalo de nuevo.</string>
<string name="notif_success_sending">Mensaje enviado a %1$s!</string> <string name="notif_success_sending">Mensaje enviado a %1$s!</string>
<string name="msg_log_out">Saliendo de tu cuenta...</string> <string name="msg_log_out">Saliendo de tu cuenta</string>
</resources> </resources>
...@@ -193,6 +193,10 @@ ...@@ -193,6 +193,10 @@
// TODO: Add proper translation. // TODO: Add proper translation.
<string name="permission_starring_not_allowed">Starring is not allowed</string> <string name="permission_starring_not_allowed">Starring is not allowed</string>
<!-- Search message -->
<!-- TODO Add proper translation-->
<string name="title_search_message">Search message</string>
<!-- Favorite/Unfavorite chat room --> <!-- Favorite/Unfavorite chat room -->
<!-- TODO Add proper translation--> <!-- TODO Add proper translation-->
<string name="title_favorite_chat">Favorite chat</string> <string name="title_favorite_chat">Favorite chat</string>
...@@ -287,5 +291,6 @@ ...@@ -287,5 +291,6 @@
<string name="notif_action_reply_hint">RÉPONDRE</string> <string name="notif_action_reply_hint">RÉPONDRE</string>
<string name="notif_error_sending">La réponse a échoué. Veuillez réessayer.</string> <string name="notif_error_sending">La réponse a échoué. Veuillez réessayer.</string>
<string name="notif_success_sending">Message envoyé à %1$s!</string> <string name="notif_success_sending">Message envoyé à %1$s!</string>
<string name="msg_log_out">Logging out...</string> <!-- TODO Add proper translation-->
<string name="msg_log_out">Logging out…</string>
</resources> </resources>
...@@ -174,6 +174,10 @@ ...@@ -174,6 +174,10 @@
<string name="permission_pinning_not_allowed">पिनि करने की अनुमति नहीं है</string> <string name="permission_pinning_not_allowed">पिनि करने की अनुमति नहीं है</string>
<string name="permission_starring_not_allowed">तारांकित की अनुमति नहीं है</string> <string name="permission_starring_not_allowed">तारांकित की अनुमति नहीं है</string>
<!-- Search message -->
<!-- TODO Add proper translation-->
<string name="title_search_message">Search message</string>
<!-- Favorite/Unfavorite chat room --> <!-- Favorite/Unfavorite chat room -->
<string name="title_favorite_chat">पसंदीदा चैट</string> <string name="title_favorite_chat">पसंदीदा चैट</string>
<string name="title_unfavorite_chat">नापसंद चैट</string> <string name="title_unfavorite_chat">नापसंद चैट</string>
...@@ -264,5 +268,6 @@ ...@@ -264,5 +268,6 @@
<string name="notif_action_reply_hint">जवाब</string> <string name="notif_action_reply_hint">जवाब</string>
<string name="notif_error_sending">उत्तर विफल हुआ है। कृपया फिर से प्रयास करें।</string> <string name="notif_error_sending">उत्तर विफल हुआ है। कृपया फिर से प्रयास करें।</string>
<string name="notif_success_sending">संदेश भेजा गया %1$s!</string> <string name="notif_success_sending">संदेश भेजा गया %1$s!</string>
<string name="msg_log_out">Logging out...</string> <!-- TODO Add proper translation-->
<string name="msg_log_out">Logging out…</string>
</resources> </resources>
\ No newline at end of file
...@@ -155,7 +155,6 @@ ...@@ -155,7 +155,6 @@
// TODO:Add proper translation. // TODO:Add proper translation.
<string name="message_credentials_saved_successfully">Credentials saved successfully</string> <string name="message_credentials_saved_successfully">Credentials saved successfully</string>
<!-- Message actions --> <!-- Message actions -->
<string name="action_msg_reply">Responder</string> <string name="action_msg_reply">Responder</string>
<string name="action_msg_edit">Editar</string> <string name="action_msg_edit">Editar</string>
...@@ -176,6 +175,9 @@ ...@@ -176,6 +175,9 @@
<string name="permission_pinning_not_allowed">Pinagem não permitida</string> <string name="permission_pinning_not_allowed">Pinagem não permitida</string>
<string name="permission_starring_not_allowed">Favoritar não permitido</string> <string name="permission_starring_not_allowed">Favoritar não permitido</string>
<!-- Search message -->
<string name="title_search_message">Procurar mensagem</string>
<!-- Favorite/Unfavorite chat room --> <!-- Favorite/Unfavorite chat room -->
<string name="title_favorite_chat">Favoritar canal</string> <string name="title_favorite_chat">Favoritar canal</string>
<string name="title_unfavorite_chat">Desfavoritar canal</string> <string name="title_unfavorite_chat">Desfavoritar canal</string>
...@@ -266,5 +268,5 @@ ...@@ -266,5 +268,5 @@
<string name="notif_action_reply_hint">RESPONDER</string> <string name="notif_action_reply_hint">RESPONDER</string>
<string name="notif_error_sending">Falha ao enviar a mensagem.</string> <string name="notif_error_sending">Falha ao enviar a mensagem.</string>
<string name="notif_success_sending">Mensagem enviada para %1$s!</string> <string name="notif_success_sending">Mensagem enviada para %1$s!</string>
<string name="msg_log_out">Deslogando...</string> <string name="msg_log_out">Deslogando</string>
</resources> </resources>
...@@ -171,6 +171,10 @@ ...@@ -171,6 +171,10 @@
<string name="permission_pinning_not_allowed">Прикрепление запрещено</string> <string name="permission_pinning_not_allowed">Прикрепление запрещено</string>
<string name="permission_starring_not_allowed">Отмечивание запрещено</string> <string name="permission_starring_not_allowed">Отмечивание запрещено</string>
<!-- Search message -->
<!-- TODO Add proper translation-->
<string name="title_search_message">Search message</string>
<!-- Favorite/Unfavorite chat room --> <!-- Favorite/Unfavorite chat room -->
<string name="title_favorite_chat">Добавить чат в избранное</string> <string name="title_favorite_chat">Добавить чат в избранное</string>
<string name="title_unfavorite_chat">Удалить чат из избранного</string> <string name="title_unfavorite_chat">Удалить чат из избранного</string>
...@@ -261,5 +265,6 @@ ...@@ -261,5 +265,6 @@
<string name="notif_action_reply_hint">ОТВЕТИТЬ</string> <string name="notif_action_reply_hint">ОТВЕТИТЬ</string>
<string name="notif_error_sending">Ошибка ответа. Пожалуйста, попробуйте еще раз.</string> <string name="notif_error_sending">Ошибка ответа. Пожалуйста, попробуйте еще раз.</string>
<string name="notif_success_sending">Сообщение отправлено %1$s!</string> <string name="notif_success_sending">Сообщение отправлено %1$s!</string>
<string name="msg_log_out">Logging out...</string> <!-- TODO Add proper translation-->
<string name="msg_log_out">Logging out…</string>
</resources> </resources>
...@@ -175,6 +175,9 @@ ...@@ -175,6 +175,9 @@
<string name="permission_pinning_not_allowed">Pinning is not allowed</string> <string name="permission_pinning_not_allowed">Pinning is not allowed</string>
<string name="permission_starring_not_allowed">Starring is not allowed</string> <string name="permission_starring_not_allowed">Starring is not allowed</string>
<!-- Search message -->
<string name="title_search_message">Search message</string>
<!-- Favorite/Unfavorite chat room --> <!-- Favorite/Unfavorite chat room -->
<string name="title_favorite_chat">Favorite chat</string> <string name="title_favorite_chat">Favorite chat</string>
<string name="title_unfavorite_chat">Unfavorite chat</string> <string name="title_unfavorite_chat">Unfavorite chat</string>
......
...@@ -9,10 +9,8 @@ ...@@ -9,10 +9,8 @@
<item name="android:statusBarColor">@color/colorPrimaryDark</item> <item name="android:statusBarColor">@color/colorPrimaryDark</item>
<item name="windowActionModeOverlay">true</item> <item name="windowActionModeOverlay">true</item>
</style>
<style name="ToolbarTheme" parent="Base.Widget.AppCompat.Toolbar"> <item name="searchViewStyle">@style/ChatRoom.SearchView</item>
<item name="android:colorAccent">@color/colorLightTheme</item>
</style> </style>
<style name="AuthenticationTheme" parent="Theme.AppCompat.NoActionBar"> <style name="AuthenticationTheme" parent="Theme.AppCompat.NoActionBar">
...@@ -75,6 +73,13 @@ ...@@ -75,6 +73,13 @@
<item name="android:paddingStart">@dimen/edit_text_margin</item> <item name="android:paddingStart">@dimen/edit_text_margin</item>
</style> </style>
<style name="ChatRoom.SearchView" parent="Widget.AppCompat.SearchView">
<item name="queryHint">@string/title_search_message</item>
<item name="searchIcon">@drawable/ic_search_white_24dp</item>
<item name="searchHintIcon">@drawable/ic_search_white_24dp</item>
<item name="closeIcon">@drawable/ic_close_white_24dp</item>
</style>
<style name="ChatRooms.Header" parent="TextAppearance.AppCompat.Headline"> <style name="ChatRooms.Header" parent="TextAppearance.AppCompat.Headline">
<item name="android:textSize">16sp</item> <item name="android:textSize">16sp</item>
</style> </style>
......
ext { ext {
versions = [ versions = [
// For project configuration
java : JavaVersion.VERSION_1_8, java : JavaVersion.VERSION_1_8,
compileSdk : 28, compileSdk : 28,
targetSdk : 28, targetSdk : 28,
minSdk : 21, minSdk : 21,
buildTools : '28.0.0-rc2', buildTools : '28.0.0-rc2',
dokka : '0.9.16',
// For app
kotlin : '1.2.51', kotlin : '1.2.51',
coroutine : '0.23.1', coroutine : '0.23.1',
dokka : '0.9.16',
// Main dependencies appCompat : '1.0.0-beta01',
appCompat : '1.0.0-alpha1', recyclerview : '1.0.0-beta01',
recyclerview : '1.0.0-alpha1', constraintLayout : '2.0.0-alpha1',
material : '1.0.0-alpha1', cardview : '1.0.0-beta01',
cardview : '1.0.0-alpha1', browser : '1.0.0-beta01',
browser : '1.0.0-alpha1', androidKtx : '1.0.0-beta01',
constraintLayout : '1.1.0',
androidKtx : '1.0.0-alpha1',
dagger : '2.16', dagger : '2.16',
exoPlayer : '2.6.0',
playServices : '15.0.0',
firebase : '15.0.0', firebase : '15.0.0',
playServices : '15.0.0',
exoPlayer : '2.6.0',
flexbox : '0.3.2',
material : '1.0.0-alpha1',
room : '2.0.0-alpha1', room : '2.0.0-alpha1',
lifecycle : '2.0.0-beta01', lifecycle : '2.0.0-beta01',
rxKotlin : '2.2.0', rxKotlin : '2.2.0',
rxAndroid : '2.0.2', rxAndroid : '2.0.2',
moshi : '1.6.0', moshi : '1.6.0',
okhttp : '3.10.0', okhttp : '3.10.0',
timber : '4.7.0', timber : '4.7.0',
threeTenABP : '1.0.5', threeTenABP : '1.0.5',
rxBinding : '2.0.0', rxBinding : '2.0.0',
fresco : '1.9.0', fresco : '1.9.0',
kotshi : '1.0.2', kotshi : '1.0.2',
frescoImageViewer : '0.5.1', frescoImageViewer : '0.5.1',
markwon : '1.0.6', markwon : '1.0.6',
aVLoadingIndicatorView: '2.1.3', aVLoadingIndicatorView: '2.1.3',
flexbox : '0.3.2',
// For wearable
wear : '2.3.0',
playServicesWearable : '15.0.1',
supportWearable : '26.1.0',
// For testing // For testing
junit : '4.12', junit : '4.12',
truth : '0.36', truth : '0.36',
espresso : '3.1.0-alpha2', espresso : '3.1.0-alpha2',
mockito : '2.10.0', mockito : '2.10.0'
//For wearable
wear : '2.3.0',
playServicesWearable : '15.0.1',
supportWearable : '26.1.0'
] ]
libraries = [ libraries = [
kotlin : "org.jetbrains.kotlin:kotlin-stdlib-jre8:${versions.kotlin}", kotlin : "org.jetbrains.kotlin:kotlin-stdlib-jre8:${versions.kotlin}",
...@@ -55,12 +65,9 @@ ext { ...@@ -55,12 +65,9 @@ ext {
appCompat : "androidx.appcompat:appcompat:${versions.appCompat}", appCompat : "androidx.appcompat:appcompat:${versions.appCompat}",
recyclerview : "androidx.recyclerview:recyclerview:${versions.recyclerview}", recyclerview : "androidx.recyclerview:recyclerview:${versions.recyclerview}",
material : "com.google.android.material:material:${versions.material}",
constraintlayout : "androidx.constraintlayout:constraintlayout:${versions.constraintLayout}", constraintlayout : "androidx.constraintlayout:constraintlayout:${versions.constraintLayout}",
cardview : "androidx.cardview:cardview:${versions.cardview}", cardview : "androidx.cardview:cardview:${versions.cardview}",
flexbox : "com.google.android:flexbox:${versions.flexbox}",
browser : "androidx.browser:browser:${versions.browser}", browser : "androidx.browser:browser:${versions.browser}",
androidKtx : "androidx.core:core-ktx:${versions.androidKtx}", androidKtx : "androidx.core:core-ktx:${versions.androidKtx}",
dagger : "com.google.dagger:dagger:${versions.dagger}", dagger : "com.google.dagger:dagger:${versions.dagger}",
...@@ -70,6 +77,8 @@ ext { ...@@ -70,6 +77,8 @@ ext {
fcm : "com.google.firebase:firebase-messaging:${versions.firebase}", fcm : "com.google.firebase:firebase-messaging:${versions.firebase}",
playServicesAuth : "com.google.android.gms:play-services-auth:${versions.playServices}", playServicesAuth : "com.google.android.gms:play-services-auth:${versions.playServices}",
exoPlayer : "com.google.android.exoplayer:exoplayer:${versions.exoPlayer}", exoPlayer : "com.google.android.exoplayer:exoplayer:${versions.exoPlayer}",
flexbox : "com.google.android:flexbox:${versions.flexbox}",
material : "com.google.android.material:material:${versions.material}",
room : "androidx.room:room-runtime:${versions.room}", room : "androidx.room:room-runtime:${versions.room}",
roomProcessor : "androidx.room:room-compiler:${versions.room}", roomProcessor : "androidx.room:room-compiler:${versions.room}",
...@@ -103,7 +112,7 @@ ext { ...@@ -103,7 +112,7 @@ ext {
aVLoadingIndicatorView: "com.wang.avi:library:${versions.aVLoadingIndicatorView}", aVLoadingIndicatorView: "com.wang.avi:library:${versions.aVLoadingIndicatorView}",
//For the wear app // For wearable
wearable : "com.google.android.support:wearable:${versions.wear}", wearable : "com.google.android.support:wearable:${versions.wear}",
playServicesWearable : "com.google.android.gms:play-services-wearable:${versions.playServicesWearable}", playServicesWearable : "com.google.android.gms:play-services-wearable:${versions.playServicesWearable}",
percentLayout : "com.android.support:percent:${versions.supportWearable}", percentLayout : "com.android.support:percent:${versions.supportWearable}",
......
...@@ -29,6 +29,10 @@ dependencies { ...@@ -29,6 +29,10 @@ dependencies {
implementation libraries.coroutines implementation libraries.coroutines
implementation libraries.coroutinesAndroid implementation libraries.coroutinesAndroid
implementation libraries.appCompat
implementation libraries.rxBinding
// TODO This is a dependency from the core module, but the util module are unable to get that dependencies. Check why it is occurring since transitive is enable by default // TODO This is a dependency from the core module, but the util module are unable to get that dependencies. Check why it is occurring since transitive is enable by default
implementation libraries.lifecycleExtensions implementation libraries.lifecycleExtensions
kapt libraries.lifecycleCompiler kapt libraries.lifecycleCompiler
......
package chat.rocket.android.util.extensions package chat.rocket.android.util.extension
import android.widget.EditText import android.widget.EditText
import com.jakewharton.rxbinding2.widget.RxTextView import com.jakewharton.rxbinding2.widget.RxTextView
......
package chat.rocket.android.util.extension
import androidx.appcompat.widget.SearchView
fun SearchView.onQueryTextListener(queryListener: (String) -> Unit) {
return this.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
queryListener(query)
return true
}
override fun onQueryTextChange(newText: String): Boolean {
queryListener(newText)
return true
}
})
}
\ 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