Unverified Commit e9c2fc4a authored by Rafael Kellermann Streit's avatar Rafael Kellermann Streit Committed by GitHub

Merge branch 'develop-2.x' into empty-pin-msg

parents b431750d 96b63e4b
...@@ -6,7 +6,7 @@ import android.app.Service ...@@ -6,7 +6,7 @@ import android.app.Service
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.content.edit import androidx.core.content.edit
import chat.rocket.android.BuildConfig import chat.rocket.android.BuildConfig
import chat.rocket.android.app.migration.RealmMigration import chat.rocket.android.app.migration.RealmMigration
import chat.rocket.android.app.migration.RocketChatLibraryModule import chat.rocket.android.app.migration.RocketChatLibraryModule
......
package chat.rocket.android.authentication.infraestructure package chat.rocket.android.authentication.infraestructure
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.content.edit import androidx.core.content.edit
import chat.rocket.android.authentication.domain.model.TokenModel import chat.rocket.android.authentication.domain.model.TokenModel
import chat.rocket.android.server.domain.TokenRepository import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.common.model.Token import chat.rocket.common.model.Token
......
package chat.rocket.android.chatroom.adapter
import android.content.Intent
import android.net.Uri
import android.view.View
import androidx.core.view.isGone
import androidx.core.view.isVisible
import chat.rocket.android.chatroom.viewmodel.AuthorAttachmentViewModel
import chat.rocket.android.util.extensions.content
import chat.rocket.android.widget.emoji.EmojiReactionListener
import chat.rocket.common.util.ifNull
import kotlinx.android.synthetic.main.item_author_attachment.view.*
class AuthorAttachmentViewHolder(itemView: View,
listener: ActionsListener,
reactionListener: EmojiReactionListener? = null)
: BaseViewHolder<AuthorAttachmentViewModel>(itemView, listener, reactionListener) {
init {
with(itemView) {
setupActionMenu(author_attachment_container)
setupActionMenu(text_fields)
setupActionMenu(text_author_name)
}
}
override fun bindViews(data: AuthorAttachmentViewModel) {
with(itemView) {
data.icon?.let { icon ->
author_icon.isVisible = true
author_icon.setImageURI(icon)
}.ifNull {
author_icon.isGone = true
}
author_icon.setImageURI(data.icon)
text_author_name.content = data.name
data.fields?.let { fields ->
text_fields.content = fields
text_fields.isVisible = true
}.ifNull {
text_fields.isGone = true
}
text_author_name.setOnClickListener {
it.context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(data.attachmentUrl)))
}
}
}
}
\ No newline at end of file
...@@ -53,6 +53,10 @@ class ChatRoomAdapter( ...@@ -53,6 +53,10 @@ class ChatRoomAdapter(
val view = parent.inflate(R.layout.item_message_attachment) val view = parent.inflate(R.layout.item_message_attachment)
MessageAttachmentViewHolder(view, actionsListener, reactionListener) MessageAttachmentViewHolder(view, actionsListener, reactionListener)
} }
BaseViewModel.ViewType.AUTHOR_ATTACHMENT -> {
val view = parent.inflate(R.layout.item_author_attachment)
AuthorAttachmentViewHolder(view, actionsListener, reactionListener)
}
else -> { else -> {
throw InvalidParameterException("TODO - implement for ${viewType.toViewType()}") throw InvalidParameterException("TODO - implement for ${viewType.toViewType()}")
} }
...@@ -92,6 +96,7 @@ class ChatRoomAdapter( ...@@ -92,6 +96,7 @@ class ChatRoomAdapter(
is VideoAttachmentViewHolder -> holder.bind(dataSet[position] as VideoAttachmentViewModel) is VideoAttachmentViewHolder -> holder.bind(dataSet[position] as VideoAttachmentViewModel)
is UrlPreviewViewHolder -> holder.bind(dataSet[position] as UrlPreviewViewModel) is UrlPreviewViewHolder -> holder.bind(dataSet[position] as UrlPreviewViewModel)
is MessageAttachmentViewHolder -> holder.bind(dataSet[position] as MessageAttachmentViewModel) is MessageAttachmentViewHolder -> holder.bind(dataSet[position] as MessageAttachmentViewModel)
is AuthorAttachmentViewHolder -> holder.bind(dataSet[position] as AuthorAttachmentViewModel)
} }
} }
...@@ -100,6 +105,7 @@ class ChatRoomAdapter( ...@@ -100,6 +105,7 @@ class ChatRoomAdapter(
return when (model) { return when (model) {
is MessageViewModel -> model.messageId.hashCode().toLong() is MessageViewModel -> model.messageId.hashCode().toLong()
is BaseFileAttachmentViewModel -> model.id is BaseFileAttachmentViewModel -> model.id
is AuthorAttachmentViewModel -> model.id
else -> return position.toLong() else -> return position.toLong()
} }
} }
......
package chat.rocket.android.chatroom.viewmodel
import chat.rocket.android.R
import chat.rocket.core.model.Message
import chat.rocket.core.model.attachment.AuthorAttachment
data class AuthorAttachmentViewModel(
override val attachmentUrl: String,
val id: Long,
val name: CharSequence?,
val icon: String?,
val fields: CharSequence?,
override val message: Message,
override val rawData: AuthorAttachment,
override val messageId: String,
override var reactions: List<ReactionViewModel>,
override var nextDownStreamMessage: BaseViewModel<*>? = null,
override var preview: Message? = null
) : BaseAttachmentViewModel<AuthorAttachment> {
override val viewType: Int
get() = BaseViewModel.ViewType.AUTHOR_ATTACHMENT.viewType
override val layoutId: Int
get() = R.layout.item_author_attachment
}
\ No newline at end of file
package chat.rocket.android.chatroom.viewmodel
interface BaseAttachmentViewModel<out T> : BaseViewModel<T> {
val attachmentUrl: String
}
\ No newline at end of file
package chat.rocket.android.chatroom.viewmodel package chat.rocket.android.chatroom.viewmodel
interface BaseFileAttachmentViewModel<out T> : BaseViewModel<T> { interface BaseFileAttachmentViewModel<out T> : BaseAttachmentViewModel<T> {
val attachmentUrl: String
val attachmentTitle: CharSequence val attachmentTitle: CharSequence
val id: Long val id: Long
} }
\ No newline at end of file
...@@ -20,7 +20,8 @@ interface BaseViewModel<out T> { ...@@ -20,7 +20,8 @@ interface BaseViewModel<out T> {
IMAGE_ATTACHMENT(3), IMAGE_ATTACHMENT(3),
VIDEO_ATTACHMENT(4), VIDEO_ATTACHMENT(4),
AUDIO_ATTACHMENT(5), AUDIO_ATTACHMENT(5),
MESSAGE_ATTACHMENT(6) MESSAGE_ATTACHMENT(6),
AUTHOR_ATTACHMENT(7)
} }
} }
......
...@@ -4,14 +4,20 @@ import DateTimeHelper ...@@ -4,14 +4,20 @@ import DateTimeHelper
import android.content.Context import android.content.Context
import android.graphics.Color import android.graphics.Color
import android.graphics.Typeface import android.graphics.Typeface
import android.support.v4.content.ContextCompat
import android.text.SpannableStringBuilder import android.text.SpannableStringBuilder
import android.text.style.ForegroundColorSpan import android.text.style.ForegroundColorSpan
import android.text.style.StyleSpan import android.text.style.StyleSpan
import androidx.core.text.bold
import androidx.core.text.buildSpannedString
import androidx.core.text.color
import androidx.core.text.scale
import chat.rocket.android.R import chat.rocket.android.R
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.server.domain.* import chat.rocket.android.server.domain.*
import chat.rocket.android.util.extensions.avatarUrl import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.isNotNullNorEmpty
import chat.rocket.android.widget.emoji.EmojiParser import chat.rocket.android.widget.emoji.EmojiParser
import chat.rocket.core.model.Message import chat.rocket.core.model.Message
import chat.rocket.core.model.MessageType import chat.rocket.core.model.MessageType
...@@ -39,6 +45,7 @@ class ViewModelMapper @Inject constructor(private val context: Context, ...@@ -39,6 +45,7 @@ class ViewModelMapper @Inject constructor(private val context: Context,
private val baseUrl = settings.baseUrl() private val baseUrl = settings.baseUrl()
private val token = tokenRepository.get(currentServer) private val token = tokenRepository.get(currentServer)
private val currentUsername: String? = localRepository.get(LocalRepository.CURRENT_USERNAME_KEY) private val currentUsername: String? = localRepository.get(LocalRepository.CURRENT_USERNAME_KEY)
private val secundaryTextColor = ContextCompat.getColor(context, R.color.colorSecondaryText)
suspend fun map(message: Message): List<BaseViewModel<*>> { suspend fun map(message: Message): List<BaseViewModel<*>> {
return translate(message) return translate(message)
...@@ -98,10 +105,39 @@ class ViewModelMapper @Inject constructor(private val context: Context, ...@@ -98,10 +105,39 @@ class ViewModelMapper @Inject constructor(private val context: Context,
return when (attachment) { return when (attachment) {
is FileAttachment -> mapFileAttachment(message, attachment) is FileAttachment -> mapFileAttachment(message, attachment)
is MessageAttachment -> mapMessageAttachment(message, attachment) is MessageAttachment -> mapMessageAttachment(message, attachment)
is AuthorAttachment -> mapAuthorAttachment(message, attachment)
else -> null else -> null
} }
} }
private suspend fun mapAuthorAttachment(message: Message, attachment: AuthorAttachment): AuthorAttachmentViewModel {
return with(attachment) {
val content = stripMessageQuotes(message)
val fieldsText = fields?.let {
buildSpannedString {
it.forEachIndexed { index, field ->
bold { append(field.title) }
append("\n")
if (field.value.isNotEmpty()) {
append(field.value)
}
if (index != it.size - 1) { // it is not the last one, append a new line
append("\n\n")
}
}
}
}
val id = attachmentId(message, attachment)
AuthorAttachmentViewModel(attachmentUrl = url, id = id, name = authorName,
icon = authorIcon, fields = fieldsText, message = message, rawData = attachment,
messageId = message.id, reactions = getReactions(message),
preview = message.copy(message = content.message))
}
}
private suspend fun mapMessageAttachment(message: Message, attachment: MessageAttachment): MessageAttachmentViewModel { private suspend fun mapMessageAttachment(message: Message, attachment: MessageAttachment): MessageAttachmentViewModel {
val attachmentAuthor = attachment.author val attachmentAuthor = attachment.author
val time = attachment.timestamp?.let { getTime(it) } val time = attachment.timestamp?.let { getTime(it) }
...@@ -136,7 +172,7 @@ class ViewModelMapper @Inject constructor(private val context: Context, ...@@ -136,7 +172,7 @@ class ViewModelMapper @Inject constructor(private val context: Context,
} }
} }
private fun attachmentId(message: Message, attachment: FileAttachment): Long { private fun attachmentId(message: Message, attachment: Attachment): Long {
return "${message.id}_${attachment.url}".hashCode().toLong() return "${message.id}_${attachment.url}".hashCode().toLong()
} }
...@@ -218,11 +254,21 @@ class ViewModelMapper @Inject constructor(private val context: Context, ...@@ -218,11 +254,21 @@ class ViewModelMapper @Inject constructor(private val context: Context,
} }
private fun getSenderName(message: Message): CharSequence { private fun getSenderName(message: Message): CharSequence {
if (!message.senderAlias.isNullOrEmpty()) { val username = message.sender?.username
return message.senderAlias!! message.senderAlias.isNotNullNorEmpty { alias ->
return buildSpannedString {
append(alias)
username?.let {
append(" ")
scale(0.8f) {
color(secundaryTextColor) {
append("@$username")
}
}
}
}
} }
val username = message.sender?.username
val realName = message.sender?.name val realName = message.sender?.name
val senderName = if (settings.useRealName()) realName else username val senderName = if (settings.useRealName()) realName else username
return senderName ?: username.toString() return senderName ?: username.toString()
......
...@@ -5,7 +5,7 @@ import android.app.NotificationManager ...@@ -5,7 +5,7 @@ import android.app.NotificationManager
import android.arch.persistence.room.Room import android.arch.persistence.room.Room
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.content.systemService import androidx.core.content.systemService
import chat.rocket.android.BuildConfig import chat.rocket.android.BuildConfig
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.app.RocketChatDatabase import chat.rocket.android.app.RocketChatDatabase
...@@ -261,8 +261,7 @@ class AppModule { ...@@ -261,8 +261,7 @@ class AppModule {
SharedPreferencesAccountsRepository(preferences, moshi) SharedPreferencesAccountsRepository(preferences, moshi)
@Provides @Provides
fun provideNotificationManager(context: Context): NotificationManager = fun provideNotificationManager(context: Context): NotificationManager = context.systemService()
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
@Provides @Provides
@Singleton @Singleton
......
...@@ -22,6 +22,10 @@ import chat.rocket.core.internal.realtime.setDefaultStatus ...@@ -22,6 +22,10 @@ import chat.rocket.core.internal.realtime.setDefaultStatus
import chat.rocket.core.internal.rest.logout import chat.rocket.core.internal.rest.logout
import chat.rocket.core.internal.rest.me import chat.rocket.core.internal.rest.me
import chat.rocket.core.internal.rest.unregisterPushToken import chat.rocket.core.internal.rest.unregisterPushToken
import chat.rocket.core.model.Myself
import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.channels.Channel
import kotlinx.coroutines.experimental.launch
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
...@@ -45,6 +49,8 @@ class MainPresenter @Inject constructor( ...@@ -45,6 +49,8 @@ class MainPresenter @Inject constructor(
private val client: RocketChatClient = factory.create(currentServer) private val client: RocketChatClient = factory.create(currentServer)
private var settings: PublicSettings = getSettingsInteractor.get(serverInteractor.get()!!) private var settings: PublicSettings = getSettingsInteractor.get(serverInteractor.get()!!)
private val userDataChannel = Channel<Myself>()
fun toChatList() = navigator.toChatList() fun toChatList() = navigator.toChatList()
fun toUserProfile() = navigator.toUserProfile() fun toUserProfile() = navigator.toUserProfile()
...@@ -55,7 +61,9 @@ class MainPresenter @Inject constructor( ...@@ -55,7 +61,9 @@ class MainPresenter @Inject constructor(
checkServerInfo() checkServerInfo()
launchUI(strategy) { launchUI(strategy) {
try { try {
val me = retryIO("me") { client.me() } val me = retryIO("me") {
client.me()
}
val model = navHeaderMapper.mapToViewModel(me) val model = navHeaderMapper.mapToViewModel(me)
saveAccount(model) saveAccount(model)
view.setupNavHeader(model, getAccountsInteractor.get()) view.setupNavHeader(model, getAccountsInteractor.get())
...@@ -74,23 +82,10 @@ class MainPresenter @Inject constructor( ...@@ -74,23 +82,10 @@ class MainPresenter @Inject constructor(
} }
} }
} }
subscribeMyselfUpdates()
} }
} }
private suspend fun saveAccount(viewModel: NavHeaderViewModel) {
val icon = settings.favicon()?.let {
currentServer.serverLogoUrl(it)
}
val account = Account(
currentServer,
icon,
viewModel.serverLogo,
viewModel.userDisplayName,
viewModel.userAvatar
)
saveAccountInteractor.save(account)
}
/** /**
* Logout from current server. * Logout from current server.
*/ */
...@@ -121,24 +116,12 @@ class MainPresenter @Inject constructor( ...@@ -121,24 +116,12 @@ class MainPresenter @Inject constructor(
} }
} }
private suspend fun clearTokens() {
serverInteractor.clear()
val pushToken = localRepository.get(LocalRepository.KEY_PUSH_TOKEN)
if (pushToken != null) {
try {
retryIO("unregisterPushToken") { client.unregisterPushToken(pushToken) }
} catch (ex: Exception) {
Timber.d(ex, "Error unregistering push token")
}
}
localRepository.clearAllFromServer(currentServer)
}
fun connect() { fun connect() {
manager.connect() manager.connect()
} }
fun disconnect() { fun disconnect() {
manager.removeUserDataChannel(userDataChannel)
manager.disconnect() manager.disconnect()
} }
...@@ -175,4 +158,43 @@ class MainPresenter @Inject constructor( ...@@ -175,4 +158,43 @@ class MainPresenter @Inject constructor(
client.registerPushToken(token, getAccountsInteractor.get(), factory) client.registerPushToken(token, getAccountsInteractor.get(), factory)
} }
} }
private suspend fun saveAccount(viewModel: NavHeaderViewModel) {
val icon = settings.favicon()?.let {
currentServer.serverLogoUrl(it)
}
val account = Account(
currentServer,
icon,
viewModel.serverLogo,
viewModel.userDisplayName!!,
viewModel.userAvatar
)
saveAccountInteractor.save(account)
}
private suspend fun clearTokens() {
serverInteractor.clear()
val pushToken = localRepository.get(LocalRepository.KEY_PUSH_TOKEN)
if (pushToken != null) {
try {
retryIO("unregisterPushToken") { client.unregisterPushToken(pushToken) }
} catch (ex: Exception) {
Timber.d(ex, "Error unregistering push token")
}
}
localRepository.clearAllFromServer(currentServer)
}
private suspend fun subscribeMyselfUpdates() {
manager.addUserDataChannel(userDataChannel)
for (myself in userDataChannel) {
updateMyself(myself)
}
}
private suspend fun updateMyself(myself: Myself) {
val model = navHeaderMapper.mapToViewModel(myself)
view.setupNavHeader(model, getAccountsInteractor.get())
}
} }
\ No newline at end of file
...@@ -95,16 +95,23 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, HasSupp ...@@ -95,16 +95,23 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, HasSupp
override fun setupNavHeader(viewModel: NavHeaderViewModel, accounts: List<Account>) { override fun setupNavHeader(viewModel: NavHeaderViewModel, accounts: List<Account>) {
Timber.d("Setting up nav header: $viewModel") Timber.d("Setting up nav header: $viewModel")
with(headerLayout) { with(headerLayout) {
image_user_status.setImageDrawable( with(viewModel) {
DrawableHelper.getUserStatusDrawable( if (userStatus != null) {
viewModel.userStatus!!, image_user_status.setImageDrawable(
this.context DrawableHelper.getUserStatusDrawable(userStatus, context)
) )
) }
text_user_name.text = viewModel.userDisplayName if (userDisplayName != null) {
text_server_url.text = viewModel.serverUrl text_user_name.text = userDisplayName
image_avatar.setImageURI(viewModel.userAvatar) }
server_logo.setImageURI(viewModel.serverLogo) if (userAvatar != null) {
image_avatar.setImageURI(userAvatar)
}
if (serverLogo != null) {
server_logo.setImageURI(serverLogo)
}
text_server_url.text = viewModel.serverUrl
}
setupAccountsList(headerLayout, accounts) setupAccountsList(headerLayout, accounts)
} }
} }
......
...@@ -4,7 +4,7 @@ import chat.rocket.common.model.UserStatus ...@@ -4,7 +4,7 @@ import chat.rocket.common.model.UserStatus
data class NavHeaderViewModel( data class NavHeaderViewModel(
val userDisplayName: String, val userDisplayName: String?,
val userStatus: UserStatus?, val userStatus: UserStatus?,
val userAvatar: String?, val userAvatar: String?,
val serverUrl: String, val serverUrl: String,
......
...@@ -23,10 +23,10 @@ class NavHeaderViewModelMapper @Inject constructor( ...@@ -23,10 +23,10 @@ class NavHeaderViewModelMapper @Inject constructor(
return NavHeaderViewModel(displayName, status, avatar, currentServer, logo) return NavHeaderViewModel(displayName, status, avatar, currentServer, logo)
} }
private fun mapDisplayName(me: Myself): String { private fun mapDisplayName(me: Myself): String? {
val username = me.username val username = me.username
val realName = me.name val realName = me.name
val senderName = if (settings.useRealName()) realName else username val senderName = if (settings.useRealName()) realName else username
return senderName ?: username.toString() return senderName ?: username
} }
} }
\ No newline at end of file
...@@ -27,7 +27,7 @@ class ProfilePresenter @Inject constructor(private val view: ProfileView, ...@@ -27,7 +27,7 @@ class ProfilePresenter @Inject constructor(private val view: ProfileView,
view.showLoading() view.showLoading()
try { try {
val myself = retryIO("me") { client.me() } val myself = retryIO("me") { client.me() }
myselfId = myself.id myselfId = myself.id!!
val avatarUrl = serverUrl.avatarUrl(myself.username!!) val avatarUrl = serverUrl.avatarUrl(myself.username!!)
view.showProfile( view.showProfile(
avatarUrl, avatarUrl,
......
...@@ -5,6 +5,7 @@ import chat.rocket.core.RocketChatClient ...@@ -5,6 +5,7 @@ import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.realtime.* import chat.rocket.core.internal.realtime.*
import chat.rocket.core.internal.rest.chatRooms import chat.rocket.core.internal.rest.chatRooms
import chat.rocket.core.model.Message import chat.rocket.core.model.Message
import chat.rocket.core.model.Myself
import kotlinx.coroutines.experimental.Job import kotlinx.coroutines.experimental.Job
import kotlinx.coroutines.experimental.channels.Channel import kotlinx.coroutines.experimental.channels.Channel
import kotlinx.coroutines.experimental.launch import kotlinx.coroutines.experimental.launch
...@@ -19,14 +20,15 @@ class ConnectionManager(internal val client: RocketChatClient) { ...@@ -19,14 +20,15 @@ class ConnectionManager(internal val client: RocketChatClient) {
private val roomAndSubscriptionChannels = ArrayList<Channel<StreamMessage<BaseRoom>>>() private val roomAndSubscriptionChannels = ArrayList<Channel<StreamMessage<BaseRoom>>>()
private val roomMessagesChannels = LinkedHashMap<String, Channel<Message>>() private val roomMessagesChannels = LinkedHashMap<String, Channel<Message>>()
private val userDataChannels = ArrayList<Channel<Myself>>()
private val subscriptionIdMap = HashMap<String, String>() private val subscriptionIdMap = HashMap<String, String>()
private var subscriptionId: String? = null private var subscriptionId: String? = null
private var roomsId: String? = null private var roomsId: String? = null
private var userId: String? = null
fun connect() { fun connect() {
if (connectJob?.isActive == true if (connectJob?.isActive == true && (state !is State.Disconnected)) {
&& (state !is State.Disconnected)) {
Timber.d("Already connected, just returning...") Timber.d("Already connected, just returning...")
return return
} }
...@@ -52,6 +54,11 @@ class ConnectionManager(internal val client: RocketChatClient) { ...@@ -52,6 +54,11 @@ class ConnectionManager(internal val client: RocketChatClient) {
roomsId = id roomsId = id
} }
client.subscribeUserDataChanges { _, id ->
Timber.d("Subscribed to the user: $id")
userId = id
}
resubscribeRooms() resubscribeRooms()
} }
is State.Waiting -> { is State.Waiting -> {
...@@ -92,6 +99,15 @@ class ConnectionManager(internal val client: RocketChatClient) { ...@@ -92,6 +99,15 @@ class ConnectionManager(internal val client: RocketChatClient) {
} }
} }
launch(parent = connectJob) {
for (myself in client.userDataChannel) {
Timber.d("Got userData")
for (channel in userDataChannels) {
channel.send(myself)
}
}
}
client.connect() client.connect()
// Broadcast initial state... // Broadcast initial state...
...@@ -125,6 +141,10 @@ class ConnectionManager(internal val client: RocketChatClient) { ...@@ -125,6 +141,10 @@ class ConnectionManager(internal val client: RocketChatClient) {
fun removeRoomsAndSubscriptionsChannel(channel: Channel<StreamMessage<BaseRoom>>) = roomAndSubscriptionChannels.remove(channel) fun removeRoomsAndSubscriptionsChannel(channel: Channel<StreamMessage<BaseRoom>>) = roomAndSubscriptionChannels.remove(channel)
fun addUserDataChannel(channel: Channel<Myself>) = userDataChannels.add(channel)
fun removeUserDataChannel(channel: Channel<Myself>) = userDataChannels.remove(channel)
fun subscribeRoomMessages(roomId: String, channel: Channel<Message>) { fun subscribeRoomMessages(roomId: String, channel: Channel<Message>) {
val oldSub = roomMessagesChannels.put(roomId, channel) val oldSub = roomMessagesChannels.put(roomId, channel)
if (oldSub != null) { if (oldSub != null) {
......
package chat.rocket.android.server.infraestructure package chat.rocket.android.server.infraestructure
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.content.edit import androidx.core.content.edit
import chat.rocket.android.server.domain.AccountsRepository import chat.rocket.android.server.domain.AccountsRepository
import chat.rocket.android.server.domain.model.Account import chat.rocket.android.server.domain.model.Account
import com.squareup.moshi.Moshi import com.squareup.moshi.Moshi
......
...@@ -25,7 +25,7 @@ class PasswordPresenter @Inject constructor (private val view: PasswordView, ...@@ -25,7 +25,7 @@ class PasswordPresenter @Inject constructor (private val view: PasswordView,
val me = retryIO("me") { client.me() } val me = retryIO("me") { client.me() }
retryIO("updateProfile(${me.id})") { retryIO("updateProfile(${me.id})") {
client.updateProfile(me.id, null, null, password, null) client.updateProfile(me.id!!, null, null, password, null)
} }
view.showPasswordSuccessfullyUpdatedMessage() view.showPasswordSuccessfullyUpdatedMessage()
......
package chat.rocket.android.util.extensions
inline fun CharSequence?.isNotNullNorEmpty(block: (CharSequence) -> Unit) {
if (this != null && this.isNotEmpty()) {
block(this)
}
}
\ No newline at end of file
...@@ -8,7 +8,7 @@ import android.os.Bundle ...@@ -8,7 +8,7 @@ import android.os.Bundle
import android.support.v7.app.AppCompatActivity import android.support.v7.app.AppCompatActivity
import android.webkit.WebView import android.webkit.WebView
import android.webkit.WebViewClient import android.webkit.WebViewClient
import androidx.net.toUri import androidx.core.net.toUri
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.util.extensions.decodeUrl import chat.rocket.android.util.extensions.decodeUrl
import chat.rocket.android.util.extensions.toJsonObject import chat.rocket.android.util.extensions.toJsonObject
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android" <shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"> android:shape="rectangle">
<solid android:color="@color/colorPrimary" /> <solid android:color="@color/quoteBar" />
<size <size
android:width="4dp" android:width="4dp"
android:height="4dp" /> android:height="4dp" />
......
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/author_attachment_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:paddingBottom="@dimen/message_item_top_and_bottom_padding"
android:paddingEnd="@dimen/screen_edge_left_and_right_padding"
android:paddingStart="@dimen/screen_edge_left_and_right_padding"
android:paddingTop="@dimen/message_item_top_and_bottom_padding">
<View
android:id="@+id/quote_bar"
android:layout_width="4dp"
android:layout_height="0dp"
android:layout_marginStart="56dp"
android:background="@drawable/quote_vertical_bar"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/recycler_view_reactions"/>
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/author_icon"
android:layout_width="8dp"
android:layout_height="8dp"
android:layout_marginTop="6dp"
android:layout_marginStart="8dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="@id/quote_bar"
tools:src="@tools:sample/avatars"/>
<TextView
android:id="@+id/text_author_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:textColor="@color/colorAccent"
android:textAppearance="@style/TextAppearance.AppCompat.Body2"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@id/author_icon"
app:layout_constraintEnd_toEndOf="parent"
tools:text="#5571 - User profile from SSO must not have password change option" />
<TextView
android:id="@+id/text_fields"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:visibility="gone"
android:layout_marginTop="4dp"
app:layout_constraintTop_toBottomOf="@id/text_author_name"
app:layout_constraintStart_toStartOf="@id/text_author_name"
app:layout_constraintEnd_toEndOf="parent"
tools:visibility="visible" />
<include
layout="@layout/layout_reactions"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@id/quote_bar"
app:layout_constraintTop_toBottomOf="@id/text_fields" />
</android.support.constraint.ConstraintLayout>
\ No newline at end of file
...@@ -39,6 +39,8 @@ ...@@ -39,6 +39,8 @@
<color name="colorEmojiIcon">#FF767676</color> <color name="colorEmojiIcon">#FF767676</color>
<color name="quoteBar">#A0A0A0</color>
<!-- Suggestions --> <!-- Suggestions -->
<color name="suggestion_background_color">@android:color/white</color> <color name="suggestion_background_color">@android:color/white</color>
......
...@@ -10,7 +10,7 @@ buildscript { ...@@ -10,7 +10,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.1.0' classpath 'com.android.tools.build:gradle:3.1.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}"
classpath "org.jetbrains.dokka:dokka-gradle-plugin:${versions.dokka}" classpath "org.jetbrains.dokka:dokka-gradle-plugin:${versions.dokka}"
classpath 'com.google.gms:google-services:3.2.0' classpath 'com.google.gms:google-services:3.2.0'
......
...@@ -11,7 +11,7 @@ ext { ...@@ -11,7 +11,7 @@ ext {
// Main dependencies // Main dependencies
support : '27.1.0', support : '27.1.0',
constraintLayout : '1.0.2', constraintLayout : '1.0.2',
androidKtx : '0.2', androidKtx : '0.3',
dagger : '2.14.1', dagger : '2.14.1',
exoPlayer : '2.6.0', exoPlayer : '2.6.0',
playServices : '11.8.0', playServices : '11.8.0',
......
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