Commit 2cd3446d authored by Leonardo Aramaki's avatar Leonardo Aramaki

Fix url markdown parsing and change style for usernames

parent 37795ffb
......@@ -13,6 +13,7 @@ import chat.rocket.common.RocketChatTwoFactorException
import chat.rocket.common.util.ifNull
import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.rest.login
import chat.rocket.core.internal.rest.me
import chat.rocket.core.internal.rest.registerPushToken
import javax.inject.Inject
......@@ -93,7 +94,9 @@ class LoginPresenter @Inject constructor(private val view: LoginView,
try {
val token = client.login(usernameOrEmail, password)
val me = client.me()
multiServerRepository.save(server, TokenModel(token.userId, token.authToken))
localRepository.save(LocalRepository.USERNAME_KEY, me.username)
registerPushToken()
navigator.toChatList()
} catch (exception: RocketChatException) {
......
......@@ -12,6 +12,7 @@ import chat.rocket.common.RocketChatException
import chat.rocket.common.util.ifNull
import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.rest.login
import chat.rocket.core.internal.rest.me
import chat.rocket.core.internal.rest.registerPushToken
import chat.rocket.core.internal.rest.signup
import javax.inject.Inject
......@@ -51,6 +52,8 @@ class SignupPresenter @Inject constructor(private val view: SignupView,
try {
client.signup(email, name, username, password) // TODO This function returns a user so should we save it?
client.login(username, password) // TODO This function returns a user token so should we save it?
val me = client.me()
localRepository.save(LocalRepository.USERNAME_KEY, me.username)
registerPushToken()
navigator.toChatList()
} catch (exception: RocketChatException) {
......
......@@ -12,6 +12,7 @@ import android.text.style.StyleSpan
import chat.rocket.android.R
import chat.rocket.android.helper.MessageParser
import chat.rocket.android.helper.UrlHelper
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.server.domain.MessagesRepository
import chat.rocket.android.server.domain.SITE_URL
import chat.rocket.android.server.domain.useRealName
......@@ -29,7 +30,8 @@ data class MessageViewModel(val context: Context,
private val message: Message,
private val settings: Map<String, Value<Any>>,
private val parser: MessageParser,
private val messagesRepository: MessagesRepository) {
private val messagesRepository: MessagesRepository,
private val localRepository: LocalRepository) {
val id: String = message.id
val roomId: String = message.roomId
val time: CharSequence
......@@ -46,8 +48,10 @@ data class MessageViewModel(val context: Context,
var attachmentTimestamp: Long? = null
var isSystemMessage: Boolean = false
var isPinned: Boolean = false
var currentUsername: String? = null
init {
currentUsername = localRepository.get(LocalRepository.USERNAME_KEY)
sender = getSenderName()
time = getTime(message.timestamp)
isPinned = message.pinned
......@@ -153,9 +157,9 @@ data class MessageViewModel(val context: Context,
var quoteViewModel: MessageViewModel? = null
if (quote != null) {
val quoteMessage: Message = quote!!
quoteViewModel = MessageViewModel(context, token, quoteMessage, settings, parser, messagesRepository)
quoteViewModel = MessageViewModel(context, token, quoteMessage, settings, parser, messagesRepository, localRepository)
}
return parser.renderMarkdown(message.message, quoteViewModel, urlsWithMeta)
return parser.renderMarkdown(message.message, quoteViewModel, currentUsername)
}
private fun getSystemMessage(content: String): CharSequence {
......
......@@ -2,6 +2,7 @@ package chat.rocket.android.chatroom.viewmodel
import android.content.Context
import chat.rocket.android.helper.MessageParser
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.server.domain.MessagesRepository
import chat.rocket.core.TokenRepository
import chat.rocket.core.model.Message
......@@ -13,7 +14,8 @@ import javax.inject.Inject
class MessageViewModelMapper @Inject constructor(private val context: Context,
private val tokenRepository: TokenRepository,
private val messageParser: MessageParser,
private val messagesRepository: MessagesRepository) {
private val messagesRepository: MessagesRepository,
private val localRepository: LocalRepository) {
suspend fun mapToViewModel(message: Message, settings: Map<String, Value<Any>>): MessageViewModel = withContext(CommonPool) {
MessageViewModel(
......@@ -22,11 +24,18 @@ class MessageViewModelMapper @Inject constructor(private val context: Context,
message,
settings,
messageParser,
messagesRepository
messagesRepository,
localRepository
)
}
suspend fun mapToViewModelList(messageList: List<Message>, settings: Map<String, Value<Any>>): List<MessageViewModel> {
return messageList.map { MessageViewModel(context, tokenRepository.get(), it, settings, messageParser, messagesRepository) }
return messageList.map { MessageViewModel(context,
tokenRepository.get(),
it,
settings,
messageParser,
messagesRepository,
localRepository) }
}
}
\ No newline at end of file
......@@ -15,7 +15,6 @@ import android.text.style.*
import android.view.View
import chat.rocket.android.R
import chat.rocket.android.chatroom.viewmodel.MessageViewModel
import chat.rocket.core.model.url.Url
import org.commonmark.node.BlockQuote
import ru.noties.markwon.Markwon
import ru.noties.markwon.SpannableBuilder
......@@ -28,7 +27,9 @@ import javax.inject.Inject
class MessageParser @Inject constructor(val context: Application, private val configuration: SpannableConfiguration) {
private val parser = Markwon.createParser()
private val usernameRegex = Pattern.compile("([^\\S]|^)+(@[\\w.]+)",
private val regexUsername = Pattern.compile("([^\\S]|^)+(@[\\w.]+)",
Pattern.MULTILINE or Pattern.CASE_INSENSITIVE)
private val regexLink = Pattern.compile("(https?:\\/\\/)?(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-z]{2,6}\\b([-a-zA-Z0-9@:%_\\+.~#?&/=]*)",
Pattern.MULTILINE or Pattern.CASE_INSENSITIVE)
/**
......@@ -40,14 +41,19 @@ class MessageParser @Inject constructor(val context: Application, private val co
*
* @return A Spannable with the parsed markdown.
*/
fun renderMarkdown(text: String, quote: MessageViewModel? = null, urls: List<Url>? = null): CharSequence {
fun renderMarkdown(text: String, quote: MessageViewModel? = null, selfUsername: String? = null): CharSequence {
val builder = SpannableBuilder()
var content: String = text
// Replace all url links to markdown url syntax.
if (urls != null) {
for (url in urls) {
content = content.replace(url.url, "[${url.url}](${url.url})")
val matcher = regexLink.matcher(content)
val consumed = mutableListOf<String>()
while (matcher.find()) {
val link = matcher.group(0)
// skip usernames
if (!link.startsWith("@") && !consumed.contains(link)) {
content = content.replace(link, "[$link]($link)")
consumed.add(link)
}
}
......@@ -62,18 +68,22 @@ class MessageParser @Inject constructor(val context: Application, private val co
}
val result = builder.text()
applySpans(result)
applySpans(result, selfUsername)
return result
}
private fun applySpans(text: CharSequence) {
val matcher = usernameRegex.matcher(text)
private fun applySpans(text: CharSequence, currentUser: String?) {
val matcher = regexUsername.matcher(text)
val result = text as Spannable
while (matcher.find()) {
val user = matcher.group(2)
val start = matcher.start(2)
//TODO: should check if username actually exists prior to applying.
result.setSpan(UsernameClickableSpan(), start, start + user.length, 0)
val linkColor = context.resources.getColor(R.color.linkTextColor)
val linkBackgroundColor = context.resources.getColor(R.color.linkBackgroundColor)
val referSelf = currentUser != null && "@$currentUser" == user
val usernameSpan = UsernameClickableSpan(linkBackgroundColor, linkColor, referSelf)
result.setSpan(usernameSpan, start, start + user.length, 0)
}
}
......@@ -164,13 +174,23 @@ class MessageParser @Inject constructor(val context: Application, private val co
}
}
class UsernameClickableSpan : ClickableSpan() {
class UsernameClickableSpan(private val linkBackgroundColor: Int,
private val linkTextColor: Int,
private val referSelf: Boolean) : ClickableSpan() {
override fun onClick(widget: View) {
//TODO: Implement action when clicking on username, like showing user profile.
}
override fun updateDrawState(ds: TextPaint) {
ds.color = ds.linkColor
if (referSelf) {
ds.color = Color.WHITE
ds.typeface = Typeface.DEFAULT_BOLD
ds.bgColor = linkTextColor
} else {
ds.color = linkTextColor
ds.bgColor = linkBackgroundColor
}
ds.isUnderlineText = false
}
......
......@@ -6,6 +6,7 @@ interface LocalRepository {
const val KEY_PUSH_TOKEN = "KEY_PUSH_TOKEN"
const val TOKEN_KEY = "token_"
const val SETTINGS_KEY = "settings_"
const val USERNAME_KEY = "my_username"
}
fun save(key: String, value: String?)
......
......@@ -20,5 +20,6 @@ class SharedPrefsLocalRepository(private val preferences: SharedPreferences) : L
clear(LocalRepository.KEY_PUSH_TOKEN)
clear(LocalRepository.TOKEN_KEY + server)
clear(LocalRepository.SETTINGS_KEY + server)
clear(LocalRepository.USERNAME_KEY + server)
}
}
\ No newline at end of file
......@@ -21,4 +21,7 @@
<color name="darkGray">#a0a0a0</color>
<color name="actionMenuColor">#727272</color>
<color name="linkTextColor">#FF074481</color>
<color name="linkBackgroundColor">#30074481</color>
</resources>
\ 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