Commit 1f901f3c authored by Filipe de Lima Brito's avatar Filipe de Lima Brito

Merge branch 'develop' of github.com:RocketChat/Rocket.Chat.Android into...

Merge branch 'develop' of github.com:RocketChat/Rocket.Chat.Android into new/listen-to-typing-status
parents e7fca8c1 9f55d568
...@@ -76,7 +76,7 @@ abstract class BaseViewHolder<T : BaseViewModel<*>>( ...@@ -76,7 +76,7 @@ abstract class BaseViewHolder<T : BaseViewModel<*>>(
fun onActionSelected(item: MenuItem, message: Message) fun onActionSelected(item: MenuItem, message: Message)
} }
private val longClickListener = { view: View -> private val onClickListener = { view: View ->
if (data?.message?.isSystemMessage() == false) { if (data?.message?.isSystemMessage() == false) {
val menuItems = view.context.inflate(R.menu.message_actions).toList() val menuItems = view.context.inflate(R.menu.message_actions).toList()
menuItems.find { it.itemId == R.id.action_menu_msg_pin_unpin }?.apply { menuItems.find { it.itemId == R.id.action_menu_msg_pin_unpin }?.apply {
...@@ -87,11 +87,11 @@ abstract class BaseViewHolder<T : BaseViewModel<*>>( ...@@ -87,11 +87,11 @@ abstract class BaseViewHolder<T : BaseViewModel<*>>(
val adapter = ActionListAdapter(menuItems, this@BaseViewHolder) val adapter = ActionListAdapter(menuItems, this@BaseViewHolder)
BottomSheetMenu(adapter).show(view.context) BottomSheetMenu(adapter).show(view.context)
} }
true
} }
internal fun setupActionMenu(view: View) { internal fun setupActionMenu(view: View) {
if (listener.isActionsEnabled()) { if (listener.isActionsEnabled()) {
view.setOnClickListener(onClickListener)
if (view is ViewGroup) { if (view is ViewGroup) {
for (child in view.children) { for (child in view.children) {
if (child !is RecyclerView && child.id != R.id.recycler_view_reactions) { if (child !is RecyclerView && child.id != R.id.recycler_view_reactions) {
...@@ -99,7 +99,6 @@ abstract class BaseViewHolder<T : BaseViewModel<*>>( ...@@ -99,7 +99,6 @@ abstract class BaseViewHolder<T : BaseViewModel<*>>(
} }
} }
} }
view.setOnLongClickListener(longClickListener)
} }
} }
......
...@@ -12,6 +12,7 @@ import chat.rocket.android.chatroom.viewmodel.suggestion.CommandSuggestionViewMo ...@@ -12,6 +12,7 @@ import chat.rocket.android.chatroom.viewmodel.suggestion.CommandSuggestionViewMo
import chat.rocket.android.chatroom.viewmodel.suggestion.PeopleSuggestionViewModel import chat.rocket.android.chatroom.viewmodel.suggestion.PeopleSuggestionViewModel
import chat.rocket.android.core.behaviours.showMessage import chat.rocket.android.core.behaviours.showMessage
import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.helper.UserHelper
import chat.rocket.android.infrastructure.LocalRepository import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.infrastructure.username import chat.rocket.android.infrastructure.username
import chat.rocket.android.server.domain.* import chat.rocket.android.server.domain.*
...@@ -49,12 +50,13 @@ class ChatRoomPresenter @Inject constructor( ...@@ -49,12 +50,13 @@ class ChatRoomPresenter @Inject constructor(
private val navigator: ChatRoomNavigator, private val navigator: ChatRoomNavigator,
private val strategy: CancelStrategy, private val strategy: CancelStrategy,
private val getChatRoomsInteractor: GetChatRoomsInteractor, private val getChatRoomsInteractor: GetChatRoomsInteractor,
private val permissions: GetPermissionsInteractor, private val permissions: PermissionsInteractor,
private val uriInteractor: UriInteractor, private val uriInteractor: UriInteractor,
private val messagesRepository: MessagesRepository, private val messagesRepository: MessagesRepository,
private val usersRepository: UsersRepository, private val usersRepository: UsersRepository,
private val roomsRepository: RoomRepository, private val roomsRepository: RoomRepository,
private val localRepository: LocalRepository, private val localRepository: LocalRepository,
private val userHelper: UserHelper,
private val mapper: ViewModelMapper, private val mapper: ViewModelMapper,
private val jobSchedulerInteractor: JobSchedulerInteractor, private val jobSchedulerInteractor: JobSchedulerInteractor,
getSettingsInteractor: GetSettingsInteractor, getSettingsInteractor: GetSettingsInteractor,
...@@ -70,12 +72,19 @@ class ChatRoomPresenter @Inject constructor( ...@@ -70,12 +72,19 @@ class ChatRoomPresenter @Inject constructor(
private var chatRoomId: String? = null private var chatRoomId: String? = null
private var chatRoomType: String? = null private var chatRoomType: String? = null
private val stateChannel = Channel<State>() private val stateChannel = Channel<State>()
private var typingStatusSubscriptionId: String? = null private var typingStatusSubscriptionId: String? = null
private var lastState = manager.state private var lastState = manager.state
private var typingStatusList = arrayListOf<String>() private var typingStatusList = arrayListOf<String>()
fun setupChatRoom() {
launchUI(strategy) {
val canPost = permissions.canPostToReadOnlyChannels()
view.onRoomChanged(canPost)
}
}
fun loadMessages(chatRoomId: String, chatRoomType: String, offset: Long = 0) { fun loadMessages(chatRoomId: String, chatRoomType: String, offset: Long = 0) {
this.chatRoomId = chatRoomId this.chatRoomId = chatRoomId
this.chatRoomType = chatRoomType this.chatRoomType = chatRoomType
...@@ -134,7 +143,7 @@ class ChatRoomPresenter @Inject constructor( ...@@ -134,7 +143,7 @@ class ChatRoomPresenter @Inject constructor(
// ignore message for now, will receive it on the stream // ignore message for now, will receive it on the stream
val id = UUID.randomUUID().toString() val id = UUID.randomUUID().toString()
val message = if (messageId == null) { val message = if (messageId == null) {
val username = localRepository.username() val username = userHelper.username()
val newMessage = Message( val newMessage = Message(
id = id, id = id,
roomId = chatRoomId, roomId = chatRoomId,
...@@ -547,7 +556,8 @@ class ChatRoomPresenter @Inject constructor( ...@@ -547,7 +556,8 @@ class ChatRoomPresenter @Inject constructor(
launchUI(strategy) { launchUI(strategy) {
try { try {
retryIO("joinChat($chatRoomId)") { client.joinChat(chatRoomId) } retryIO("joinChat($chatRoomId)") { client.joinChat(chatRoomId) }
view.onJoined() val canPost = permissions.canPostToReadOnlyChannels()
view.onJoined(canPost)
} catch (ex: RocketChatException) { } catch (ex: RocketChatException) {
Timber.e(ex) Timber.e(ex)
} }
...@@ -560,7 +570,7 @@ class ChatRoomPresenter @Inject constructor( ...@@ -560,7 +570,7 @@ class ChatRoomPresenter @Inject constructor(
fun react(messageId: String, emoji: String) { fun react(messageId: String, emoji: String) {
launchUI(strategy) { launchUI(strategy) {
try { try {
retryIO("toogleEmoji($messageId, $emoji)") { retryIO("toggleEmoji($messageId, $emoji)") {
client.toggleReaction(messageId, emoji.removeSurrounding(":")) client.toggleReaction(messageId, emoji.removeSurrounding(":"))
} }
} catch (ex: RocketChatException) { } catch (ex: RocketChatException) {
...@@ -691,4 +701,4 @@ class ChatRoomPresenter @Inject constructor( ...@@ -691,4 +701,4 @@ class ChatRoomPresenter @Inject constructor(
} }
} }
} }
} }
\ No newline at end of file
...@@ -121,8 +121,10 @@ interface ChatRoomView : LoadingView, MessageView { ...@@ -121,8 +121,10 @@ interface ChatRoomView : LoadingView, MessageView {
fun populateRoomSuggestions(chatRooms: List<ChatRoomSuggestionViewModel>) fun populateRoomSuggestions(chatRooms: List<ChatRoomSuggestionViewModel>)
/** /**
* This user has joined the chat callback. * This user has joined the chat callback.
*
* @param canPost Whether the user can post a message or not.
*/ */
fun onJoined() fun onJoined(canPost: Boolean)
fun showReactionsPopup(messageId: String) fun showReactionsPopup(messageId: String)
...@@ -132,4 +134,6 @@ interface ChatRoomView : LoadingView, MessageView { ...@@ -132,4 +134,6 @@ interface ChatRoomView : LoadingView, MessageView {
* @param commands The list of available commands. * @param commands The list of available commands.
*/ */
fun populateCommandSuggestions(commands: List<CommandSuggestionViewModel>) fun populateCommandSuggestions(commands: List<CommandSuggestionViewModel>)
fun onRoomChanged(canPost: Boolean)
} }
\ No newline at end of file
...@@ -27,22 +27,25 @@ fun Context.chatRoomIntent( ...@@ -27,22 +27,25 @@ fun Context.chatRoomIntent(
chatRoomType: String, chatRoomType: String,
isChatRoomReadOnly: Boolean, isChatRoomReadOnly: Boolean,
chatRoomLastSeen: Long, chatRoomLastSeen: Long,
isChatRoomSubscribed: Boolean = true isChatRoomSubscribed: Boolean = true,
isChatRoomOwner: Boolean = false
): Intent { ): Intent {
return Intent(this, ChatRoomActivity::class.java).apply { return Intent(this, ChatRoomActivity::class.java).apply {
putExtra(INTENT_CHAT_ROOM_ID, chatRoomId) putExtra(INTENT_CHAT_ROOM_ID, chatRoomId)
putExtra(INTENT_CHAT_ROOM_NAME, chatRoomName) putExtra(INTENT_CHAT_ROOM_NAME, chatRoomName)
putExtra(INTENT_CHAT_ROOM_TYPE, chatRoomType) putExtra(INTENT_CHAT_ROOM_TYPE, chatRoomType)
putExtra(INTENT_IS_CHAT_ROOM_READ_ONLY, isChatRoomReadOnly) putExtra(INTENT_CHAT_ROOM_IS_READ_ONLY, isChatRoomReadOnly)
putExtra(INTENT_CHAT_ROOM_LAST_SEEN, chatRoomLastSeen) putExtra(INTENT_CHAT_ROOM_LAST_SEEN, chatRoomLastSeen)
putExtra(INTENT_CHAT_IS_SUBSCRIBED, isChatRoomSubscribed) putExtra(INTENT_CHAT_IS_SUBSCRIBED, isChatRoomSubscribed)
putExtra(INTENT_CHAT_ROOM_IS_OWNER, isChatRoomOwner)
} }
} }
private const val INTENT_CHAT_ROOM_ID = "chat_room_id" private const val INTENT_CHAT_ROOM_ID = "chat_room_id"
private const val INTENT_CHAT_ROOM_NAME = "chat_room_name" private const val INTENT_CHAT_ROOM_NAME = "chat_room_name"
private const val INTENT_CHAT_ROOM_TYPE = "chat_room_type" private const val INTENT_CHAT_ROOM_TYPE = "chat_room_type"
private const val INTENT_IS_CHAT_ROOM_READ_ONLY = "is_chat_room_read_only" private const val INTENT_CHAT_ROOM_IS_READ_ONLY = "chat_room_is_read_only"
private const val INTENT_CHAT_ROOM_IS_OWNER = "chat_room_is_owner"
private const val INTENT_CHAT_ROOM_LAST_SEEN = "chat_room_last_seen" private const val INTENT_CHAT_ROOM_LAST_SEEN = "chat_room_last_seen"
private const val INTENT_CHAT_IS_SUBSCRIBED = "is_chat_room_subscribed" private const val INTENT_CHAT_IS_SUBSCRIBED = "is_chat_room_subscribed"
...@@ -59,6 +62,7 @@ class ChatRoomActivity : AppCompatActivity(), HasSupportFragmentInjector { ...@@ -59,6 +62,7 @@ class ChatRoomActivity : AppCompatActivity(), HasSupportFragmentInjector {
private lateinit var chatRoomType: String private lateinit var chatRoomType: String
private var isChatRoomReadOnly: Boolean = false private var isChatRoomReadOnly: Boolean = false
private var isChatRoomSubscribed: Boolean = true private var isChatRoomSubscribed: Boolean = true
private var isChatRoomOwner: Boolean = false
private var chatRoomLastSeen: Long = -1L private var chatRoomLastSeen: Long = -1L
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
...@@ -84,8 +88,11 @@ class ChatRoomActivity : AppCompatActivity(), HasSupportFragmentInjector { ...@@ -84,8 +88,11 @@ class ChatRoomActivity : AppCompatActivity(), HasSupportFragmentInjector {
chatRoomType = intent.getStringExtra(INTENT_CHAT_ROOM_TYPE) chatRoomType = intent.getStringExtra(INTENT_CHAT_ROOM_TYPE)
requireNotNull(chatRoomType) { "no chat_room_type provided in Intent extras" } requireNotNull(chatRoomType) { "no chat_room_type provided in Intent extras" }
isChatRoomReadOnly = intent.getBooleanExtra(INTENT_IS_CHAT_ROOM_READ_ONLY, true) isChatRoomReadOnly = intent.getBooleanExtra(INTENT_CHAT_ROOM_IS_READ_ONLY, true)
requireNotNull(chatRoomType) { "no is_chat_room_read_only provided in Intent extras" } requireNotNull(isChatRoomReadOnly) { "no chat_room_is_read_only provided in Intent extras" }
isChatRoomOwner = intent.getBooleanExtra(INTENT_CHAT_ROOM_IS_OWNER, false)
requireNotNull(isChatRoomOwner) { "no chat_room_is_owner provided in Intent extras" }
setupToolbar() setupToolbar()
...@@ -96,7 +103,7 @@ class ChatRoomActivity : AppCompatActivity(), HasSupportFragmentInjector { ...@@ -96,7 +103,7 @@ class ChatRoomActivity : AppCompatActivity(), HasSupportFragmentInjector {
if (supportFragmentManager.findFragmentByTag(TAG_CHAT_ROOM_FRAGMENT) == null) { if (supportFragmentManager.findFragmentByTag(TAG_CHAT_ROOM_FRAGMENT) == null) {
addFragment(TAG_CHAT_ROOM_FRAGMENT, R.id.fragment_container) { addFragment(TAG_CHAT_ROOM_FRAGMENT, R.id.fragment_container) {
newInstance(chatRoomId, chatRoomName, chatRoomType, isChatRoomReadOnly, chatRoomLastSeen, newInstance(chatRoomId, chatRoomName, chatRoomType, isChatRoomReadOnly, chatRoomLastSeen,
isChatRoomSubscribed) isChatRoomSubscribed, isChatRoomOwner)
} }
} }
} }
......
...@@ -50,7 +50,8 @@ fun newInstance( ...@@ -50,7 +50,8 @@ fun newInstance(
chatRoomType: String, chatRoomType: String,
isChatRoomReadOnly: Boolean, isChatRoomReadOnly: Boolean,
chatRoomLastSeen: Long, chatRoomLastSeen: Long,
isSubscribed: Boolean = true isSubscribed: Boolean = true,
isChatRoomOwner: Boolean = false
): Fragment { ): Fragment {
return ChatRoomFragment().apply { return ChatRoomFragment().apply {
arguments = Bundle(1).apply { arguments = Bundle(1).apply {
...@@ -60,6 +61,7 @@ fun newInstance( ...@@ -60,6 +61,7 @@ fun newInstance(
putBoolean(BUNDLE_IS_CHAT_ROOM_READ_ONLY, isChatRoomReadOnly) putBoolean(BUNDLE_IS_CHAT_ROOM_READ_ONLY, isChatRoomReadOnly)
putLong(BUNDLE_CHAT_ROOM_LAST_SEEN, chatRoomLastSeen) putLong(BUNDLE_CHAT_ROOM_LAST_SEEN, chatRoomLastSeen)
putBoolean(BUNDLE_CHAT_ROOM_IS_SUBSCRIBED, isSubscribed) putBoolean(BUNDLE_CHAT_ROOM_IS_SUBSCRIBED, isSubscribed)
putBoolean(BUNDLE_CHAT_ROOM_IS_OWNER, isChatRoomOwner)
} }
} }
} }
...@@ -71,6 +73,7 @@ private const val BUNDLE_IS_CHAT_ROOM_READ_ONLY = "is_chat_room_read_only" ...@@ -71,6 +73,7 @@ private const val BUNDLE_IS_CHAT_ROOM_READ_ONLY = "is_chat_room_read_only"
private const val REQUEST_CODE_FOR_PERFORM_SAF = 42 private const val REQUEST_CODE_FOR_PERFORM_SAF = 42
private const val BUNDLE_CHAT_ROOM_LAST_SEEN = "chat_room_last_seen" private const val BUNDLE_CHAT_ROOM_LAST_SEEN = "chat_room_last_seen"
private const val BUNDLE_CHAT_ROOM_IS_SUBSCRIBED = "chat_room_is_subscribed" private const val BUNDLE_CHAT_ROOM_IS_SUBSCRIBED = "chat_room_is_subscribed"
private const val BUNDLE_CHAT_ROOM_IS_OWNER = "chat_room_is_owner"
class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiReactionListener { class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiReactionListener {
@Inject @Inject
...@@ -83,6 +86,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -83,6 +86,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
private lateinit var chatRoomType: String private lateinit var chatRoomType: String
private var isSubscribed: Boolean = true private var isSubscribed: Boolean = true
private var isChatRoomReadOnly: Boolean = false private var isChatRoomReadOnly: Boolean = false
private var isChatRoomOwner: Boolean = false
private lateinit var emojiKeyboardPopup: EmojiKeyboardPopup private lateinit var emojiKeyboardPopup: EmojiKeyboardPopup
private var chatRoomLastSeen: Long = -1 private var chatRoomLastSeen: Long = -1
private lateinit var actionSnackbar: ActionSnackbar private lateinit var actionSnackbar: ActionSnackbar
...@@ -122,6 +126,8 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -122,6 +126,8 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
isChatRoomReadOnly = bundle.getBoolean(BUNDLE_IS_CHAT_ROOM_READ_ONLY) isChatRoomReadOnly = bundle.getBoolean(BUNDLE_IS_CHAT_ROOM_READ_ONLY)
isSubscribed = bundle.getBoolean(BUNDLE_CHAT_ROOM_IS_SUBSCRIBED) isSubscribed = bundle.getBoolean(BUNDLE_CHAT_ROOM_IS_SUBSCRIBED)
chatRoomLastSeen = bundle.getLong(BUNDLE_CHAT_ROOM_LAST_SEEN) chatRoomLastSeen = bundle.getLong(BUNDLE_CHAT_ROOM_LAST_SEEN)
isChatRoomOwner = bundle.getBoolean(BUNDLE_CHAT_ROOM_IS_OWNER)
} else { } else {
requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" } requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" }
} }
...@@ -140,11 +146,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -140,11 +146,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
setupToolbar(chatRoomName) setupToolbar(chatRoomName)
presenter.setupChatRoom()
presenter.loadMessages(chatRoomId, chatRoomType) presenter.loadMessages(chatRoomId, chatRoomType)
presenter.loadChatRooms() presenter.loadChatRooms()
setupRecyclerView() setupRecyclerView()
setupFab() setupFab()
setupMessageComposer()
setupSuggestionsView() setupSuggestionsView()
setupActionSnackbar() setupActionSnackbar()
activity?.apply { activity?.apply {
...@@ -243,6 +249,10 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -243,6 +249,10 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
} }
} }
override fun onRoomChanged(canPost: Boolean) {
setupMessageComposer(isChatRoomOwner || canPost)
}
private fun toggleNoChatView(size: Int) { private fun toggleNoChatView(size: Int) {
if (size == 0){ if (size == 0){
image_chat_icon.setVisible(true) image_chat_icon.setVisible(true)
...@@ -564,12 +574,12 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -564,12 +574,12 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
} }
} }
override fun onJoined() { override fun onJoined(canPost: Boolean) {
ui { ui {
input_container.setVisible(true) input_container.setVisible(true)
button_join_chat.setVisible(false) button_join_chat.setVisible(false)
isSubscribed = true isSubscribed = true
setupMessageComposer() setupMessageComposer(isChatRoomOwner)
} }
} }
...@@ -600,8 +610,8 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -600,8 +610,8 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
} }
} }
private fun setupMessageComposer() { private fun setupMessageComposer(canPost: Boolean) {
if (isChatRoomReadOnly) { if (!canPost && isChatRoomReadOnly) {
text_room_is_read_only.setVisible(true) text_room_is_read_only.setVisible(true)
input_container.setVisible(false) input_container.setVisible(false)
} else if (!isSubscribed) { } else if (!isSubscribed) {
......
...@@ -313,6 +313,7 @@ class ViewModelMapper @Inject constructor( ...@@ -313,6 +313,7 @@ class ViewModelMapper @Inject constructor(
} }
private fun getSystemMessage(message: Message): CharSequence { private fun getSystemMessage(message: Message): CharSequence {
println(message)
val content = when (message.type) { val content = when (message.type) {
//TODO: Add implementation for Welcome type. //TODO: Add implementation for Welcome type.
is MessageType.MessageRemoved -> context.getString(R.string.message_removed) is MessageType.MessageRemoved -> context.getString(R.string.message_removed)
...@@ -322,6 +323,8 @@ class ViewModelMapper @Inject constructor( ...@@ -322,6 +323,8 @@ class ViewModelMapper @Inject constructor(
is MessageType.RoomNameChanged -> context.getString(R.string.message_room_name_changed, message.message, message.sender?.username) is MessageType.RoomNameChanged -> context.getString(R.string.message_room_name_changed, message.message, message.sender?.username)
is MessageType.UserRemoved -> context.getString(R.string.message_user_removed_by, message.message, message.sender?.username) is MessageType.UserRemoved -> context.getString(R.string.message_user_removed_by, message.message, message.sender?.username)
is MessageType.MessagePinned -> context.getString(R.string.message_pinned) is MessageType.MessagePinned -> context.getString(R.string.message_pinned)
is MessageType.UserMuted -> context.getString(R.string.message_muted, message.message, message.sender?.username)
is MessageType.UserUnMuted -> context.getString(R.string.message_unmuted, message.message, message.sender?.username)
else -> { else -> {
throw InvalidParameterException("Invalid message type: ${message.type}") throw InvalidParameterException("Invalid message type: ${message.type}")
} }
......
package chat.rocket.android.chatrooms.presentation package chat.rocket.android.chatrooms.presentation
import chat.rocket.android.R
import chat.rocket.android.chatroom.viewmodel.ViewModelMapper import chat.rocket.android.chatroom.viewmodel.ViewModelMapper
import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.core.lifecycle.CancelStrategy
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.helper.UserHelper
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.main.presentation.MainNavigator import chat.rocket.android.main.presentation.MainNavigator
import chat.rocket.android.server.domain.* import chat.rocket.android.server.domain.*
import chat.rocket.android.server.infraestructure.ConnectionManager import chat.rocket.android.server.infraestructure.ConnectionManager
...@@ -23,6 +26,8 @@ import chat.rocket.core.internal.model.Subscription ...@@ -23,6 +26,8 @@ import chat.rocket.core.internal.model.Subscription
import chat.rocket.core.internal.realtime.socket.model.State import chat.rocket.core.internal.realtime.socket.model.State
import chat.rocket.core.internal.realtime.socket.model.StreamMessage import chat.rocket.core.internal.realtime.socket.model.StreamMessage
import chat.rocket.core.internal.realtime.socket.model.Type import chat.rocket.core.internal.realtime.socket.model.Type
import chat.rocket.core.internal.rest.me
import chat.rocket.core.internal.rest.permissions
import chat.rocket.core.internal.rest.spotlight import chat.rocket.core.internal.rest.spotlight
import chat.rocket.core.model.ChatRoom import chat.rocket.core.model.ChatRoom
import chat.rocket.core.model.Room import chat.rocket.core.model.Room
...@@ -45,6 +50,9 @@ class ChatRoomsPresenter @Inject constructor( ...@@ -45,6 +50,9 @@ class ChatRoomsPresenter @Inject constructor(
private val refreshSettingsInteractor: RefreshSettingsInteractor, private val refreshSettingsInteractor: RefreshSettingsInteractor,
private val viewModelMapper: ViewModelMapper, private val viewModelMapper: ViewModelMapper,
private val jobSchedulerInteractor: JobSchedulerInteractor, private val jobSchedulerInteractor: JobSchedulerInteractor,
private val permissionsInteractor: PermissionsInteractor,
private val localRepository: LocalRepository,
private val userHelper: UserHelper,
settingsRepository: SettingsRepository, settingsRepository: SettingsRepository,
factory: ConnectionManagerFactory factory: ConnectionManagerFactory
) { ) {
...@@ -69,6 +77,8 @@ class ChatRoomsPresenter @Inject constructor( ...@@ -69,6 +77,8 @@ class ChatRoomsPresenter @Inject constructor(
refreshSettingsInteractor.refresh(currentServer) refreshSettingsInteractor.refresh(currentServer)
} }
view.updateChatRooms(getUserChatRooms()) view.updateChatRooms(getUserChatRooms())
val permissions = retryIO { client.permissions() }
permissionsInteractor.saveAll(permissions)
} catch (ex: RocketChatException) { } catch (ex: RocketChatException) {
ex.message?.let { ex.message?.let {
view.showMessage(it) view.showMessage(it)
...@@ -85,7 +95,8 @@ class ChatRoomsPresenter @Inject constructor( ...@@ -85,7 +95,8 @@ class ChatRoomsPresenter @Inject constructor(
} }
fun loadChatRoom(chatRoom: ChatRoom) { fun loadChatRoom(chatRoom: ChatRoom) {
val roomName = if (chatRoom.type is RoomType.DirectMessage val isDirectMessage = chatRoom.type is RoomType.DirectMessage
val roomName = if (isDirectMessage
&& chatRoom.fullName != null && chatRoom.fullName != null
&& settings.useRealName()) { && settings.useRealName()) {
chatRoom.fullName!! chatRoom.fullName!!
...@@ -93,10 +104,40 @@ class ChatRoomsPresenter @Inject constructor( ...@@ -93,10 +104,40 @@ class ChatRoomsPresenter @Inject constructor(
chatRoom.name chatRoom.name
} }
navigator.toChatRoom(chatRoom.id, roomName, launchUI(strategy) {
chatRoom.type.toString(), chatRoom.readonly ?: false, val myself = getCurrentUser()
chatRoom.lastSeen ?: -1, if (myself?.username == null) {
chatRoom.open) view.showMessage(R.string.msg_generic_error)
} else {
val isChatRoomOwner = chatRoom.user?.username == myself.username || isDirectMessage
navigator.toChatRoom(chatRoom.id, roomName,
chatRoom.type.toString(), chatRoom.readonly ?: false,
chatRoom.lastSeen ?: -1,
chatRoom.open, isChatRoomOwner)
}
}
}
private suspend fun getCurrentUser(): User? {
userHelper.user()?.let {
return it
}
try {
val myself = retryIO { client.me() }
val user = User(
id = myself.id,
username = myself.username,
name = myself.name,
status = myself.status,
utcOffset = myself.utcOffset,
emails = null,
roles = myself.roles
)
localRepository.saveCurrentUser(url = currentServer, user = user)
} catch (ex: RocketChatException) {
Timber.e(ex)
}
return null
} }
/** /**
...@@ -415,7 +456,7 @@ class ChatRoomsPresenter @Inject constructor( ...@@ -415,7 +456,7 @@ class ChatRoomsPresenter @Inject constructor(
val newRoom = ChatRoom( val newRoom = ChatRoom(
id = room.id, id = room.id,
type = room.type, type = room.type,
user = room.user ?: user, user = room.user,
status = getActiveUsersInteractor.getActiveUserByUsername( status = getActiveUsersInteractor.getActiveUserByUsername(
currentServer, currentServer,
room.name ?: name room.name ?: name
...@@ -454,7 +495,7 @@ class ChatRoomsPresenter @Inject constructor( ...@@ -454,7 +495,7 @@ class ChatRoomsPresenter @Inject constructor(
val newRoom = ChatRoom( val newRoom = ChatRoom(
id = subscription.roomId, id = subscription.roomId,
type = subscription.type, type = subscription.type,
user = subscription.user ?: user, user = user,
status = getActiveUsersInteractor.getActiveUserByUsername( status = getActiveUsersInteractor.getActiveUserByUsername(
currentServer, currentServer,
subscription.name subscription.name
......
...@@ -25,10 +25,13 @@ import com.facebook.drawee.view.SimpleDraweeView ...@@ -25,10 +25,13 @@ import com.facebook.drawee.view.SimpleDraweeView
import kotlinx.android.synthetic.main.item_chat.view.* import kotlinx.android.synthetic.main.item_chat.view.*
import kotlinx.android.synthetic.main.unread_messages_badge.view.* import kotlinx.android.synthetic.main.unread_messages_badge.view.*
class ChatRoomsAdapter(private val context: Context, class ChatRoomsAdapter(
private val settings: PublicSettings, private val context: Context,
private val localRepository: LocalRepository, private val settings: PublicSettings,
private val listener: (ChatRoom) -> Unit) : RecyclerView.Adapter<ChatRoomsAdapter.ViewHolder>() { private val localRepository: LocalRepository,
private val listener: (ChatRoom) -> Unit
) : RecyclerView.Adapter<ChatRoomsAdapter.ViewHolder>() {
var dataSet: MutableList<ChatRoom> = ArrayList() var dataSet: MutableList<ChatRoom> = ArrayList()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder = ViewHolder(parent.inflate(R.layout.item_chat)) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder = ViewHolder(parent.inflate(R.layout.item_chat))
......
...@@ -24,7 +24,6 @@ import chat.rocket.android.helper.SharedPreferenceHelper ...@@ -24,7 +24,6 @@ import chat.rocket.android.helper.SharedPreferenceHelper
import chat.rocket.android.infrastructure.LocalRepository import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.server.domain.GetCurrentServerInteractor import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.SettingsRepository import chat.rocket.android.server.domain.SettingsRepository
import chat.rocket.android.server.domain.showLastMessage
import chat.rocket.android.util.extensions.* import chat.rocket.android.util.extensions.*
import chat.rocket.android.widget.DividerItemDecoration import chat.rocket.android.widget.DividerItemDecoration
import chat.rocket.common.model.RoomType import chat.rocket.common.model.RoomType
...@@ -38,10 +37,14 @@ import timber.log.Timber ...@@ -38,10 +37,14 @@ import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
class ChatRoomsFragment : Fragment(), ChatRoomsView { class ChatRoomsFragment : Fragment(), ChatRoomsView {
@Inject lateinit var presenter: ChatRoomsPresenter @Inject
@Inject lateinit var serverInteractor: GetCurrentServerInteractor lateinit var presenter: ChatRoomsPresenter
@Inject lateinit var settingsRepository: SettingsRepository @Inject
@Inject lateinit var localRepository: LocalRepository lateinit var serverInteractor: GetCurrentServerInteractor
@Inject
lateinit var settingsRepository: SettingsRepository
@Inject
lateinit var localRepository: LocalRepository
private lateinit var preferences: SharedPreferences private lateinit var preferences: SharedPreferences
private var searchView: SearchView? = null private var searchView: SearchView? = null
private val handler = Handler() private val handler = Handler()
...@@ -137,9 +140,9 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView { ...@@ -137,9 +140,9 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
}) })
val dialogSort = AlertDialog.Builder(context) val dialogSort = AlertDialog.Builder(context)
.setTitle(R.string.dialog_sort_title) .setTitle(R.string.dialog_sort_title)
.setView(dialogLayout) .setView(dialogLayout)
.setPositiveButton("Done", { dialog, _ -> dialog.dismiss() }) .setPositiveButton("Done", { dialog, _ -> dialog.dismiss() })
dialogSort.show() dialogSort.show()
} }
...@@ -147,9 +150,9 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView { ...@@ -147,9 +150,9 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
} }
private fun invalidateQueryOnSearch(){ private fun invalidateQueryOnSearch() {
searchView?.let { searchView?.let {
if (!searchView!!.isIconified){ if (!searchView!!.isIconified) {
queryChatRoomsByName(searchView!!.query.toString()) queryChatRoomsByName(searchView!!.query.toString())
} }
} }
...@@ -180,7 +183,7 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView { ...@@ -180,7 +183,7 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
ui { text_no_data_to_display.setVisible(true) } ui { text_no_data_to_display.setVisible(true) }
} }
override fun showLoading(){ override fun showLoading() {
ui { view_loading.setVisible(true) } ui { view_loading.setVisible(true) }
} }
...@@ -237,19 +240,18 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView { ...@@ -237,19 +240,18 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
ui { ui {
recycler_view.layoutManager = LinearLayoutManager(it, LinearLayoutManager.VERTICAL, false) recycler_view.layoutManager = LinearLayoutManager(it, LinearLayoutManager.VERTICAL, false)
recycler_view.addItemDecoration(DividerItemDecoration(it, recycler_view.addItemDecoration(DividerItemDecoration(it,
resources.getDimensionPixelSize(R.dimen.divider_item_decorator_bound_start), resources.getDimensionPixelSize(R.dimen.divider_item_decorator_bound_start),
resources.getDimensionPixelSize(R.dimen.divider_item_decorator_bound_end))) resources.getDimensionPixelSize(R.dimen.divider_item_decorator_bound_end)))
recycler_view.itemAnimator = DefaultItemAnimator() recycler_view.itemAnimator = DefaultItemAnimator()
// TODO - use a ViewModel Mapper instead of using settings on the adapter // TODO - use a ViewModel Mapper instead of using settings on the adapter
println(serverInteractor.get() + " -> ${settingsRepository.get(serverInteractor.get()!!).showLastMessage()}")
val baseAdapter = ChatRoomsAdapter(it, val baseAdapter = ChatRoomsAdapter(it,
settingsRepository.get(serverInteractor.get()!!), localRepository) { settingsRepository.get(serverInteractor.get()!!), localRepository) { chatRoom ->
chatRoom -> presenter.loadChatRoom(chatRoom) presenter.loadChatRoom(chatRoom)
} }
sectionedAdapter = SimpleSectionedRecyclerViewAdapter(it, sectionedAdapter = SimpleSectionedRecyclerViewAdapter(it,
R.layout.item_chatroom_header, R.id.text_chatroom_header, baseAdapter) R.layout.item_chatroom_header, R.id.text_chatroom_header, baseAdapter)
recycler_view.adapter = sectionedAdapter recycler_view.adapter = sectionedAdapter
} }
} }
......
...@@ -14,12 +14,10 @@ import chat.rocket.android.app.RocketChatDatabase ...@@ -14,12 +14,10 @@ import chat.rocket.android.app.RocketChatDatabase
import chat.rocket.android.authentication.infraestructure.SharedPreferencesMultiServerTokenRepository import chat.rocket.android.authentication.infraestructure.SharedPreferencesMultiServerTokenRepository
import chat.rocket.android.authentication.infraestructure.SharedPreferencesTokenRepository import chat.rocket.android.authentication.infraestructure.SharedPreferencesTokenRepository
import chat.rocket.android.chatroom.service.MessageService import chat.rocket.android.chatroom.service.MessageService
import chat.rocket.android.dagger.qualifier.ForFresco
import chat.rocket.android.dagger.qualifier.ForMessages import chat.rocket.android.dagger.qualifier.ForMessages
import chat.rocket.android.helper.FrescoAuthInterceptor
import chat.rocket.android.helper.MessageParser import chat.rocket.android.helper.MessageParser
import chat.rocket.android.infrastructure.LocalRepository import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.infrastructure.SharedPrefsLocalRepository import chat.rocket.android.infrastructure.SharedPreferencesLocalRepository
import chat.rocket.android.push.GroupedPush import chat.rocket.android.push.GroupedPush
import chat.rocket.android.push.PushManager import chat.rocket.android.push.PushManager
import chat.rocket.android.server.domain.* import chat.rocket.android.server.domain.*
...@@ -43,7 +41,6 @@ import com.squareup.moshi.Moshi ...@@ -43,7 +41,6 @@ import com.squareup.moshi.Moshi
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import kotlinx.coroutines.experimental.Job import kotlinx.coroutines.experimental.Job
import okhttp3.Interceptor
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor import okhttp3.logging.HttpLoggingInterceptor
import ru.noties.markwon.SpannableConfiguration import ru.noties.markwon.SpannableConfiguration
...@@ -111,32 +108,16 @@ class AppModule { ...@@ -111,32 +108,16 @@ class AppModule {
@Singleton @Singleton
fun provideOkHttpClient(logger: HttpLoggingInterceptor): OkHttpClient { fun provideOkHttpClient(logger: HttpLoggingInterceptor): OkHttpClient {
return OkHttpClient.Builder() return OkHttpClient.Builder()
.addInterceptor(logger) .addInterceptor(logger)
.connectTimeout(15, TimeUnit.SECONDS) .connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS) .readTimeout(20, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS) .writeTimeout(15, TimeUnit.SECONDS)
.build() .build()
}
@Provides
@ForFresco
@Singleton
fun provideFrescoAuthInterceptor(tokenRepository: TokenRepository, currentServerInteractor: GetCurrentServerInteractor): Interceptor {
return FrescoAuthInterceptor(tokenRepository, currentServerInteractor)
}
@Provides
@ForFresco
@Singleton
fun provideFrescoOkHttpClient(okHttpClient: OkHttpClient, @ForFresco authInterceptor: Interceptor): OkHttpClient {
return okHttpClient.newBuilder().apply {
//addInterceptor(authInterceptor)
}.build()
} }
@Provides @Provides
@Singleton @Singleton
fun provideImagePipelineConfig(context: Context, @ForFresco okHttpClient: OkHttpClient): ImagePipelineConfig { fun provideImagePipelineConfig(context: Context, okHttpClient: OkHttpClient): ImagePipelineConfig {
val listeners = setOf(RequestLoggingListener()) val listeners = setOf(RequestLoggingListener())
return OkHttpImagePipelineConfigFactory.newBuilder(context, okHttpClient) return OkHttpImagePipelineConfigFactory.newBuilder(context, okHttpClient)
...@@ -177,8 +158,8 @@ class AppModule { ...@@ -177,8 +158,8 @@ class AppModule {
@Provides @Provides
@Singleton @Singleton
fun provideLocalRepository(prefs: SharedPreferences): LocalRepository { fun provideLocalRepository(prefs: SharedPreferences, moshi: Moshi): LocalRepository {
return SharedPrefsLocalRepository(prefs) return SharedPreferencesLocalRepository(prefs, moshi)
} }
@Provides @Provides
...@@ -193,6 +174,12 @@ class AppModule { ...@@ -193,6 +174,12 @@ class AppModule {
return SharedPreferencesSettingsRepository(localRepository) return SharedPreferencesSettingsRepository(localRepository)
} }
@Provides
@Singleton
fun providePermissionsRepository(localRepository: LocalRepository, moshi: Moshi): PermissionsRepository {
return SharedPreferencesPermissionsRepository(localRepository, moshi)
}
@Provides @Provides
@Singleton @Singleton
fun provideRoomRepository(): RoomRepository { fun provideRoomRepository(): RoomRepository {
...@@ -258,7 +245,7 @@ class AppModule { ...@@ -258,7 +245,7 @@ class AppModule {
@Provides @Provides
@Singleton @Singleton
fun provideConfiguration(context: Application, client: OkHttpClient): SpannableConfiguration { fun provideConfiguration(context: Application): SpannableConfiguration {
val res = context.resources val res = context.resources
return SpannableConfiguration.builder(context) return SpannableConfiguration.builder(context)
.theme(SpannableTheme.builder() .theme(SpannableTheme.builder()
...@@ -273,12 +260,6 @@ class AppModule { ...@@ -273,12 +260,6 @@ class AppModule {
return MessageParser(context, configuration, settingsInteractor.get(url)) return MessageParser(context, configuration, settingsInteractor.get(url))
} }
@Provides
@Singleton
fun providePermissionInteractor(settingsRepository: SettingsRepository, serverRepository: CurrentServerRepository): GetPermissionsInteractor {
return GetPermissionsInteractor(settingsRepository, serverRepository)
}
@Provides @Provides
@Singleton @Singleton
fun provideAccountsRepository(preferences: SharedPreferences, moshi: Moshi): AccountsRepository = fun provideAccountsRepository(preferences: SharedPreferences, moshi: Moshi): AccountsRepository =
......
...@@ -3,7 +3,21 @@ package chat.rocket.android.dagger.module ...@@ -3,7 +3,21 @@ package chat.rocket.android.dagger.module
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import chat.rocket.android.infrastructure.LocalRepository import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.infrastructure.SharedPrefsLocalRepository import chat.rocket.android.infrastructure.SharedPreferencesLocalRepository
import chat.rocket.android.server.domain.CurrentServerRepository
import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.infraestructure.SharedPrefsCurrentServerRepository
import chat.rocket.android.util.AppJsonAdapterFactory
import chat.rocket.android.util.TimberLogger
import chat.rocket.common.internal.FallbackSealedClassJsonAdapter
import chat.rocket.common.internal.ISO8601Date
import chat.rocket.common.model.TimestampAdapter
import chat.rocket.common.util.CalendarISO8601Converter
import chat.rocket.common.util.Logger
import chat.rocket.common.util.PlatformLogger
import chat.rocket.core.internal.AttachmentAdapterFactory
import chat.rocket.core.internal.ReactionsAdapter
import com.squareup.moshi.Moshi
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import javax.inject.Singleton import javax.inject.Singleton
...@@ -11,14 +25,53 @@ import javax.inject.Singleton ...@@ -11,14 +25,53 @@ import javax.inject.Singleton
@Module @Module
class LocalModule { class LocalModule {
@Provides
@Singleton
fun providePlatformLogger(): PlatformLogger {
return TimberLogger
}
@Provides
@Singleton
fun provideCurrentServerRepository(prefs: SharedPreferences): CurrentServerRepository {
return SharedPrefsCurrentServerRepository(prefs)
}
@Provides
@Singleton
fun provideMoshi(
logger: PlatformLogger,
currentServerInteractor: GetCurrentServerInteractor
): Moshi {
val url = currentServerInteractor.get() ?: ""
return Moshi.Builder()
.add(FallbackSealedClassJsonAdapter.ADAPTER_FACTORY)
.add(AppJsonAdapterFactory.INSTANCE)
.add(AttachmentAdapterFactory(Logger(logger, url)))
.add(
java.lang.Long::class.java,
ISO8601Date::class.java,
TimestampAdapter(CalendarISO8601Converter())
)
.add(
Long::class.java,
ISO8601Date::class.java,
TimestampAdapter(CalendarISO8601Converter())
)
.add(ReactionsAdapter())
.build()
}
@Provides @Provides
fun provideSharedPreferences(context: Context): SharedPreferences { fun provideSharedPreferences(context: Context): SharedPreferences {
return context.getSharedPreferences("rocket.chat", Context.MODE_PRIVATE) return context.getSharedPreferences("rocket.chat", Context.MODE_PRIVATE)
} }
@Provides @Provides
@Singleton @Singleton
fun provideLocalRepository(prefs: SharedPreferences): LocalRepository { fun provideLocalRepository(sharedPreferences: SharedPreferences, moshi: Moshi): LocalRepository {
return SharedPrefsLocalRepository(prefs) return SharedPreferencesLocalRepository(sharedPreferences, moshi)
} }
} }
\ No newline at end of file
package chat.rocket.android.dagger.qualifier
import javax.inject.Qualifier
@Qualifier
@Retention(AnnotationRetention.RUNTIME)
annotation class ForFresco
\ No newline at end of file
package chat.rocket.android.helper
import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.TokenRepository
import okhttp3.Interceptor
import okhttp3.Response
class FrescoAuthInterceptor(
private val tokenRepository: TokenRepository,
private val currentServerInteractor: GetCurrentServerInteractor
) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
var request = chain.request()
currentServerInteractor.get()?.let { serverUrl ->
val token = tokenRepository.get(serverUrl)
return@let token?.let {
val url = request.url().newBuilder().apply {
addQueryParameter("rc_uid", token.userId)
addQueryParameter("rc_token", token.authToken)
}.build()
request = request.newBuilder().apply {
url(url)
}.build()
}
}
return chain.proceed(request)
}
}
\ No newline at end of file
package chat.rocket.android.helper
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.SettingsRepository
import chat.rocket.android.server.domain.useRealName
import chat.rocket.common.model.User
import javax.inject.Inject
class UserHelper @Inject constructor(
private val localRepository: LocalRepository,
private val getCurrentServerInteractor: GetCurrentServerInteractor,
settingsRepository: SettingsRepository
) {
private val settings: PublicSettings = settingsRepository.get(getCurrentServerInteractor.get()!!)
/**
* Return the display name for the given [user].
* If setting 'Use_Real_Name' is true then the real name will be given, or else
* the username without the '@' is yielded. The fallback for any case is the username, which
* could be null.
*/
fun displayName(user: User): String? {
return if (settings.useRealName()) user.name ?: user.username else user.username
}
/**
* Return current logged user's display name.
*
* @see displayName
*/
fun displayName(): String? {
user()?.let {
return displayName(it)
}
return null
}
/**
* Return current logged [User].
*/
fun user(): User? {
return localRepository.getCurrentUser(serverUrl())
}
/**
* Return the username for the current logged [User].
*/
fun username(): String? = user()?.username
/**
* Whether current [User] is admin on the current server.
*/
fun isAdmin(): Boolean {
return user()?.roles?.find { it.equals("admin", ignoreCase = true) } != null
}
private fun serverUrl(): String {
return getCurrentServerInteractor.get()!!
}
}
\ No newline at end of file
package chat.rocket.android.infrastructure package chat.rocket.android.infrastructure
import chat.rocket.common.model.User
interface LocalRepository { interface LocalRepository {
fun save(key: String, value: String?) fun save(key: String, value: String?)
...@@ -14,12 +16,16 @@ interface LocalRepository { ...@@ -14,12 +16,16 @@ interface LocalRepository {
fun getLong(key: String, defValue: Long = -1L): Long fun getLong(key: String, defValue: Long = -1L): Long
fun clear(key: String) fun clear(key: String)
fun clearAllFromServer(server: String) fun clearAllFromServer(server: String)
fun getCurrentUser(url: String): User?
fun saveCurrentUser(url: String, user: User)
companion object { companion object {
const val KEY_PUSH_TOKEN = "KEY_PUSH_TOKEN" const val KEY_PUSH_TOKEN = "KEY_PUSH_TOKEN"
const val MIGRATION_FINISHED_KEY = "MIGRATION_FINISHED_KEY" const val MIGRATION_FINISHED_KEY = "MIGRATION_FINISHED_KEY"
const val TOKEN_KEY = "token_" const val TOKEN_KEY = "token_"
const val SETTINGS_KEY = "settings_" const val SETTINGS_KEY = "settings_"
const val PERMISSIONS_KEY = "permissions_"
const val USER_KEY = "user_"
const val CURRENT_USERNAME_KEY = "username_" const val CURRENT_USERNAME_KEY = "username_"
} }
} }
......
...@@ -2,8 +2,26 @@ package chat.rocket.android.infrastructure ...@@ -2,8 +2,26 @@ package chat.rocket.android.infrastructure
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.core.content.edit import androidx.core.content.edit
import chat.rocket.common.model.User
import com.squareup.moshi.Moshi
class SharedPreferencesLocalRepository(
private val preferences: SharedPreferences,
moshi: Moshi
) : LocalRepository {
private val userAdapter = moshi.adapter(User::class.java)
override fun getCurrentUser(url: String): User? {
return get("${url}_${LocalRepository.USER_KEY}", null)?.let {
userAdapter.fromJson(it)
}
}
override fun saveCurrentUser(url: String, user: User) {
save("${url}_${LocalRepository.USER_KEY}", userAdapter.toJson(user))
}
class SharedPrefsLocalRepository(private val preferences: SharedPreferences) : LocalRepository {
override fun getBoolean(key: String, defValue: Boolean) = preferences.getBoolean(key, defValue) override fun getBoolean(key: String, defValue: Boolean) = preferences.getBoolean(key, defValue)
override fun getFloat(key: String, defValue: Float) = preferences.getFloat(key, defValue) override fun getFloat(key: String, defValue: Float) = preferences.getFloat(key, defValue)
......
...@@ -36,9 +36,10 @@ class MainNavigator(internal val activity: MainActivity) { ...@@ -36,9 +36,10 @@ class MainNavigator(internal val activity: MainActivity) {
chatRoomType: String, chatRoomType: String,
isChatRoomReadOnly: Boolean, isChatRoomReadOnly: Boolean,
chatRoomLastSeen: Long, chatRoomLastSeen: Long,
isChatRoomSubscribed: Boolean) { isChatRoomSubscribed: Boolean,
isChatRoomOwner: Boolean) {
activity.startActivity(activity.chatRoomIntent(chatRoomId, chatRoomName, chatRoomType, activity.startActivity(activity.chatRoomIntent(chatRoomId, chatRoomName, chatRoomType,
isChatRoomReadOnly, chatRoomLastSeen, isChatRoomSubscribed)) isChatRoomReadOnly, chatRoomLastSeen, isChatRoomSubscribed, isChatRoomOwner))
activity.overridePendingTransition(R.anim.open_enter, R.anim.open_exit) activity.overridePendingTransition(R.anim.open_enter, R.anim.open_exit)
} }
......
package chat.rocket.android.server.domain package chat.rocket.android.server.domain
import chat.rocket.android.helper.UserHelper
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.core.model.Permission
import javax.inject.Inject import javax.inject.Inject
class GetPermissionsInteractor @Inject constructor(private val settingsRepository: SettingsRepository, // Creating rooms
private val currentServerRepository: CurrentServerRepository) { const val CREATE_PUBLIC_CHANNELS = "create-c"
const val CREATE_DIRECT_MESSAGES = "create-d"
const val CREATE_PRIVATE_CHANNELS = "create-p"
private fun publicSettings(): PublicSettings? = settingsRepository.get(currentServerRepository.get()!!) // Messages
const val DELETE_MESSAGE = "delete-message"
const val FORCE_DELETE_MESSAGE = "force-delete-message"
const val EDIT_MESSAGE = "edit-message"
const val PIN_MESSAGE = "pin-message"
const val POST_READONLY = "post-readonly"
class PermissionsInteractor @Inject constructor(
private val settingsRepository: SettingsRepository,
private val permissionsRepository: PermissionsRepository,
private val getCurrentServerInteractor: GetCurrentServerInteractor,
private val userHelper: UserHelper
) {
private fun publicSettings(): PublicSettings? = settingsRepository.get(currentServerUrl()!!)
fun saveAll(permissions: List<Permission>) {
val url = currentServerUrl()!!
permissions.forEach { permissionsRepository.save(url, it) }
}
/** /**
* Check whether user is allowed to delete a message. * Check whether user is allowed to delete a message.
...@@ -31,4 +55,18 @@ class GetPermissionsInteractor @Inject constructor(private val settingsRepositor ...@@ -31,4 +55,18 @@ class GetPermissionsInteractor @Inject constructor(private val settingsRepositor
* Checks whether should show edited message status. * Checks whether should show edited message status.
*/ */
fun showEditedStatus() = publicSettings()?.showEditedStatus() ?: false fun showEditedStatus() = publicSettings()?.showEditedStatus() ?: false
fun canPostToReadOnlyChannels(): Boolean {
val url = getCurrentServerInteractor.get()!!
val currentUserRoles = userHelper.user()?.roles
return permissionsRepository.get(url, POST_READONLY)?.let { permission ->
currentUserRoles?.isNotEmpty() == true && permission.roles.any {
currentUserRoles.contains(it)
}
} == true || userHelper.isAdmin()
}
private fun currentServerUrl(): String? {
return getCurrentServerInteractor.get()
}
} }
\ No newline at end of file
package chat.rocket.android.server.domain
import chat.rocket.core.model.Permission
interface PermissionsRepository {
/**
* Store [permission] locally.
*
* @param url The server url from where we're interest to store the permission.
* @param permission The permission to store.
*/
fun save(url: String, permission: Permission)
/**
* Get permission given by the [permissionId] and for the server [url].
*
* @param url The server url from where we're interested on getting the permissions.
* @param permissionId the id of the permission to get.
*
* @return The interested [Permission] or null if not found.
*/
fun get(url: String, permissionId: String): Permission?
}
\ No newline at end of file
package chat.rocket.android.server.infraestructure
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.server.domain.PermissionsRepository
import chat.rocket.core.model.Permission
import com.squareup.moshi.Moshi
class SharedPreferencesPermissionsRepository(
private val localRepository: LocalRepository,
moshi: Moshi
) : PermissionsRepository {
private val adapter = moshi.adapter(Permission::class.java)
override fun save(url: String, permission: Permission) {
localRepository.save(getPermissionKey(url, permission.id), adapter.toJson(permission))
}
override fun get(url: String, permissionId: String): Permission? {
return localRepository.get(getPermissionKey(url, permissionId))?.let {
adapter.fromJson(it)
}
}
// Create a key following the pattern: settings_[url]_[permission id]
// eg.: 'settings_https://open.rocket.chat_create-p'
private fun getPermissionKey(url: String, permissionId: String): String {
return "${LocalRepository.PERMISSIONS_KEY}${url}_$permissionId"
}
}
\ No newline at end of file
...@@ -6,7 +6,9 @@ import chat.rocket.android.server.domain.PublicSettings ...@@ -6,7 +6,9 @@ import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.SettingsRepository import chat.rocket.android.server.domain.SettingsRepository
import chat.rocket.core.internal.SettingsAdapter import chat.rocket.core.internal.SettingsAdapter
class SharedPreferencesSettingsRepository(private val localRepository: LocalRepository) : SettingsRepository { class SharedPreferencesSettingsRepository(
private val localRepository: LocalRepository
) : SettingsRepository {
private val adapter = SettingsAdapter().lenient() private val adapter = SettingsAdapter().lenient()
......
...@@ -130,6 +130,8 @@ ...@@ -130,6 +130,8 @@
<string name="message_welcome">Bienvenido %s</string> <string name="message_welcome">Bienvenido %s</string>
<string name="message_removed">Mensaje eliminado</string> <string name="message_removed">Mensaje eliminado</string>
<string name="message_pinned">Fijado una mensaje:</string> <string name="message_pinned">Fijado una mensaje:</string>
<string name="message_muted">Usuario %1$s silenciado por %2$s</string>
<string name="message_unmuted">Usuario %1$s no silenciado por %2$s</string>
<!-- Message actions --> <!-- Message actions -->
<string name="action_msg_reply">Respuesta</string> <string name="action_msg_reply">Respuesta</string>
......
...@@ -130,6 +130,8 @@ ...@@ -130,6 +130,8 @@
<string name="message_welcome">Bienvenue %s</string> <string name="message_welcome">Bienvenue %s</string>
<string name="message_removed">Message supprimé</string> <string name="message_removed">Message supprimé</string>
<string name="message_pinned">Épinglé un message:</string> <string name="message_pinned">Épinglé un message:</string>
<string name="message_muted">Utilisateur %1$s mis en sourdine par %2$s</string>
<string name="message_unmuted">Utilisateur %1$s non muté par %2$s</string>
<!-- Message actions --> <!-- Message actions -->
<string name="action_msg_reply">Répondre</string> <string name="action_msg_reply">Répondre</string>
......
...@@ -132,6 +132,8 @@ ...@@ -132,6 +132,8 @@
<string name="message_welcome">%s का स्वागत करते हैं</string> <string name="message_welcome">%s का स्वागत करते हैं</string>
<string name="message_removed">संदेश हटाया गया</string> <string name="message_removed">संदेश हटाया गया</string>
<string name="message_pinned">एक संदेश पिन किया:</string> <string name="message_pinned">एक संदेश पिन किया:</string>
<string name="message_muted">उपयोगकर्ता %1$s %2$s द्वारा म्यूट किया गया</string>
<string name="message_unmuted">उपयोगकर्ता %1$s %2$s द्वारा अनम्यूट किया गया</string>
<!-- Message actions --> <!-- Message actions -->
<string name="action_msg_reply">जवाब दें</string> <string name="action_msg_reply">जवाब दें</string>
......
...@@ -117,11 +117,13 @@ ...@@ -117,11 +117,13 @@
<string name="message_room_name_changed">Nome da sala alterado para: %1$s por %2$s</string> <string name="message_room_name_changed">Nome da sala alterado para: %1$s por %2$s</string>
<string name="message_user_added_by">Usuário %1$s adicionado por %2$s</string> <string name="message_user_added_by">Usuário %1$s adicionado por %2$s</string>
<string name="message_user_removed_by">Usuário %1$s removido por %2$s</string> <string name="message_user_removed_by">Usuário %1$s removido por %2$s</string>
<string name="message_user_left">Saiu da sala.</string> <string name="message_user_left">Saiu da sala</string>
<string name="message_user_joined_channel">Entrou na sala.</string> <string name="message_user_joined_channel">Entrou na sala</string>
<string name="message_welcome">Bem-vindo, %s</string> <string name="message_welcome">Bem-vindo, %s</string>
<string name="message_removed">Mensagem removida</string> <string name="message_removed">Mensagem removida</string>
<string name="message_pinned">Pinou uma mensagem:</string> <string name="message_pinned">Pinou uma mensagem:</string>
<string name="message_muted">Usuário %1$s entrou no modo mudo por %2$s</string>
<string name="message_unmuted">Usuário %1$s saiu do modo mudo por %2$s</string>
<!-- Message actions --> <!-- Message actions -->
<string name="action_msg_reply">Responder</string> <string name="action_msg_reply">Responder</string>
...@@ -129,11 +131,11 @@ ...@@ -129,11 +131,11 @@
<string name="action_msg_copy">Copiar</string> <string name="action_msg_copy">Copiar</string>
<string name="action_msg_quote">Citar</string> <string name="action_msg_quote">Citar</string>
<string name="action_msg_delete">Remover</string> <string name="action_msg_delete">Remover</string>
<string name="action_msg_pin">Fixar Mensagem</string> <string name="action_msg_pin">Pinar mensagem</string>
<string name="action_msg_unpin">Desafixar Mensagem</string> <string name="action_msg_unpin">Despinar mensagem</string>
<string name="action_msg_star">Favoritar Mensagem</string> <string name="action_msg_star">Favoritar mensagem</string>
<string name="action_msg_share">Compartilhar</string> <string name="action_msg_share">Compartilhar</string>
<string name="action_title_editing">Editando Mensagem</string> <string name="action_title_editing">Editando mensagem</string>
<string name="action_msg_add_reaction">Adicionar reação</string> <string name="action_msg_add_reaction">Adicionar reação</string>
<!-- Permission messages --> <!-- Permission messages -->
...@@ -154,7 +156,7 @@ ...@@ -154,7 +156,7 @@
<!-- Socket status --> <!-- Socket status -->
<string name="status_connected">Conectado</string> <string name="status_connected">Conectado</string>
<string name="status_disconnected">Desconetado</string> <string name="status_disconnected">Desconectado</string>
<string name="status_connecting">Conectando</string> <string name="status_connecting">Conectando</string>
<string name="status_authenticating">Autenticando</string> <string name="status_authenticating">Autenticando</string>
<string name="status_disconnecting">Desconectando</string> <string name="status_disconnecting">Desconectando</string>
...@@ -171,7 +173,7 @@ ...@@ -171,7 +173,7 @@
<string name="Slash_Tableflip_Description">Exibir (╯°□°)╯︵ ┻━┻</string> <string name="Slash_Tableflip_Description">Exibir (╯°□°)╯︵ ┻━┻</string>
<string name="Slash_TableUnflip_Description">Exibir ┬─┬ ノ( ゜-゜ノ)</string> <string name="Slash_TableUnflip_Description">Exibir ┬─┬ ノ( ゜-゜ノ)</string>
<string name="Create_A_New_Channel">Criar um novo canal</string> <string name="Create_A_New_Channel">Criar um novo canal</string>
<string name="Show_the_keyboard_shortcut_list">Show the keyboard shortcut list</string> <string name="Show_the_keyboard_shortcut_list">Exibir a lista de atalhos do teclado</string>
<string name="Invite_user_to_join_channel_all_from"> do [#canal] para entrar neste</string> <string name="Invite_user_to_join_channel_all_from"> do [#canal] para entrar neste</string>
<string name="Invite_user_to_join_channel_all_to">Convidar todos os usuários deste canal para entrar no [#canal]</string> <string name="Invite_user_to_join_channel_all_to">Convidar todos os usuários deste canal para entrar no [#canal]</string>
<string name="Archive">Arquivar</string> <string name="Archive">Arquivar</string>
...@@ -179,8 +181,8 @@ ...@@ -179,8 +181,8 @@
<string name="Leave_the_current_channel">Sair do canal atual</string> <string name="Leave_the_current_channel">Sair do canal atual</string>
<string name="Displays_action_text">Exibir texto de ação</string> <string name="Displays_action_text">Exibir texto de ação</string>
<string name="Direct_message_someone">Enviar DM para alguém</string> <string name="Direct_message_someone">Enviar DM para alguém</string>
<string name="Mute_someone_in_room">Silenciar alguém</string> <string name="Mute_someone_in_room">Ativar o modo mudo em alguém</string>
<string name="Unmute_someone_in_room">De-silenciar alguém na sala</string> <string name="Unmute_someone_in_room">Desativar o modo mudo em alguém na sala</string>
<string name="Invite_user_to_join_channel">Convidar algum usuário para entrar neste canal</string> <string name="Invite_user_to_join_channel">Convidar algum usuário para entrar neste canal</string>
<string name="Unarchive">Desarquivar</string> <string name="Unarchive">Desarquivar</string>
<string name="Join_the_given_channel">Entrar no canal especificado</string> <string name="Join_the_given_channel">Entrar no canal especificado</string>
......
...@@ -123,6 +123,8 @@ ...@@ -123,6 +123,8 @@
<string name="message_welcome">Welcome %s</string> <string name="message_welcome">Welcome %s</string>
<string name="message_removed">Message removed</string> <string name="message_removed">Message removed</string>
<string name="message_pinned">Pinned a message:</string> <string name="message_pinned">Pinned a message:</string>
<string name="message_muted">User %1$s muted by %2$s</string>
<string name="message_unmuted">User %1$s unmuted by %2$s</string>
<!-- Message actions --> <!-- Message actions -->
<string name="action_msg_reply">Reply</string> <string name="action_msg_reply">Reply</string>
......
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