Commit 8ded46ea authored by Filipe de Lima Brito's avatar Filipe de Lima Brito

Merge branch 'beta' of github.com:RocketChat/Rocket.Chat.Android into new/wordpress-oauth-login

parents c6c0d963 1fadf89c
......@@ -11,8 +11,8 @@ import timber.log.Timber
@Parcelize
data class LoginDeepLinkInfo(
val url: String,
val userId: String,
val token: String
val userId: String?,
val token: String?
) : Parcelable
fun Intent.getLoginDeepLinkInfo(): LoginDeepLinkInfo? {
......
......@@ -134,10 +134,15 @@ class LoginPresenter @Inject constructor(
fun authenticateWithDeepLink(deepLinkInfo: LoginDeepLinkInfo) {
val serverUrl = deepLinkInfo.url
setupConnectionInfo(serverUrl)
deepLinkUserId = deepLinkInfo.userId
deepLinkToken = deepLinkInfo.token
tokenRepository.save(serverUrl, Token(deepLinkUserId, deepLinkToken))
doAuthentication(TYPE_LOGIN_DEEP_LINK)
if (deepLinkInfo.userId != null && deepLinkInfo.token != null) {
deepLinkUserId = deepLinkInfo.userId
deepLinkToken = deepLinkInfo.token
tokenRepository.save(serverUrl, Token(deepLinkUserId, deepLinkToken))
doAuthentication(TYPE_LOGIN_DEEP_LINK)
} else {
// If we don't have the login credentials, just go through normal setup and user input.
setupView()
}
}
private fun setupConnectionInfo(serverUrl: String) {
......
......@@ -104,6 +104,8 @@ class ServerFragment : Fragment(), ServerView {
override fun onDestroyView() {
super.onDestroyView()
// reset deep link info, so user can come back and log to another server...
deepLinkInfo = null
relative_layout.viewTreeObserver.removeOnGlobalLayoutListener(layoutListener)
}
......@@ -144,9 +146,9 @@ class ServerFragment : Fragment(), ServerView {
hideLoading()
AlertDialog.Builder(it)
.setMessage(getString(R.string.msg_ver_not_recommended, BuildConfig.RECOMMENDED_SERVER_VERSION))
.setPositiveButton(R.string.msg_ok, { _, _ ->
.setPositiveButton(R.string.msg_ok) { _, _ ->
performConnect()
})
}
.create()
.show()
}
......
......@@ -56,9 +56,7 @@ class AuthenticationActivity : AppCompatActivity(), HasSupportFragmentInjector {
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
val currentFragment = supportFragmentManager.findFragmentById(R.id.fragment_container)
if (currentFragment != null) {
currentFragment.onActivityResult(requestCode, resultCode, data)
}
currentFragment?.onActivityResult(requestCode, resultCode, data)
}
override fun supportFragmentInjector(): AndroidInjector<Fragment> {
......
......@@ -18,10 +18,9 @@ import java.security.InvalidParameterException
class ChatRoomAdapter(
private val roomType: String? = null,
private val roomName: String? = null,
private val presenter: ChatRoomPresenter? = null,
private val actionSelectListener: OnActionSelected? = null,
private val enableActions: Boolean = true,
private val reactionListener: EmojiReactionListener? = null,
private val context: Context? = null
private val reactionListener: EmojiReactionListener? = null
) : RecyclerView.Adapter<BaseViewHolder<*>>() {
private val dataSet = ArrayList<BaseUiModel<*>>()
......@@ -70,7 +69,7 @@ class ChatRoomAdapter(
BaseUiModel.ViewType.MESSAGE_REPLY -> {
val view = parent.inflate(R.layout.item_message_reply)
MessageReplyViewHolder(view, actionsListener, reactionListener) { roomName, permalink ->
presenter?.openDirectMessage(roomName, permalink)
actionSelectListener?.openDirectMessage(roomName, permalink)
}
}
else -> {
......@@ -212,52 +211,53 @@ class ChatRoomAdapter(
message.apply {
when (item.itemId) {
R.id.action_message_info -> {
presenter?.messageInfo(id)
actionSelectListener?.showMessageInfo(id)
}
R.id.action_message_reply -> {
if (roomName != null && roomType != null) {
presenter?.citeMessage(roomName, roomType, id, true)
actionSelectListener?.citeMessage(roomName, roomType, id, true)
}
}
R.id.action_message_quote -> {
if (roomName != null && roomType != null) {
presenter?.citeMessage(roomName, roomType, id, false)
actionSelectListener?.citeMessage(roomName, roomType, id, false)
}
}
R.id.action_message_copy -> {
presenter?.copyMessage(id)
actionSelectListener?.copyMessage(id)
}
R.id.action_message_edit -> {
presenter?.editMessage(roomId, id, message.message)
actionSelectListener?.editMessage(roomId, id, message.message)
}
R.id.action_message_star -> {
if (!item.isChecked) {
presenter?.starMessage(id)
} else {
presenter?.unstarMessage(id)
}
actionSelectListener?.toogleStar(id, !item.isChecked)
}
R.id.action_message_unpin -> {
if (!item.isChecked) {
presenter?.pinMessage(id)
} else {
presenter?.unpinMessage(id)
}
actionSelectListener?.tooglePin(id, !item.isChecked)
}
R.id.action_message_delete -> {
context?.let {
val builder = AlertDialog.Builder(it)
builder.setTitle(it.getString(R.string.msg_delete_message))
.setMessage(it.getString(R.string.msg_delete_description))
.setPositiveButton(it.getString(R.string.msg_ok)) { _, _ -> presenter?.deleteMessage(roomId, id) }
.setNegativeButton(it.getString(R.string.msg_cancel)) { _, _ -> }
.show()
}
actionSelectListener?.deleteMessage(roomId, id)
}
R.id.action_menu_msg_react -> {
actionSelectListener?.showReactions(id)
}
else -> {
TODO("Not implemented")
}
R.id.action_menu_msg_react -> presenter?.showReactions(id)
else -> TODO("Not implemented")
}
}
}
}
interface OnActionSelected {
fun showMessageInfo(id: String)
fun citeMessage(roomName: String, roomType: String, messageId: String, mentionAuthor: Boolean)
fun copyMessage(id: String)
fun editMessage(roomId: String, messageId: String, text: String)
fun toogleStar(id: String, star: Boolean)
fun tooglePin(id: String, pin: Boolean)
fun deleteMessage(roomId: String, id: String)
fun showReactions(id: String)
fun openDirectMessage(roomName: String, message: String)
}
}
\ No newline at end of file
package chat.rocket.android.chatroom.adapter
import android.net.Uri
import android.view.View
import androidx.core.view.isVisible
import chat.rocket.android.chatroom.uimodel.UrlPreviewUiModel
import chat.rocket.android.util.extensions.openTabbedUrl
import chat.rocket.android.emoji.EmojiReactionListener
import chat.rocket.android.util.extensions.content
import chat.rocket.android.util.extensions.openTabbedUrl
import kotlinx.android.synthetic.main.message_url_preview.view.*
class UrlPreviewViewHolder(itemView: View,
......@@ -42,7 +41,7 @@ class UrlPreviewViewHolder(itemView: View,
private val onClickListener = { view: View ->
if (data != null) {
view.openTabbedUrl(Uri.parse(data!!.rawData.url))
view.openTabbedUrl(data!!.rawData.url)
}
}
}
\ No newline at end of file
......@@ -1006,7 +1006,7 @@ class ChatRoomPresenter @Inject constructor(
}
}
private suspend fun subscribeTypingStatus() {
private fun subscribeTypingStatus() {
launch(CommonPool + strategy.jobs) {
client.subscribeTypingStatus(chatRoomId.toString()) { _, id ->
typingStatusSubscriptionId = id
......@@ -1019,22 +1019,25 @@ class ChatRoomPresenter @Inject constructor(
}
private fun processTypingStatus(typingStatus: Pair<String, Boolean>) {
if (!typingStatusList.any { username -> username == typingStatus.first }) {
if (typingStatus.second) {
typingStatusList.add(typingStatus.first)
}
} else {
typingStatusList.find { username -> username == typingStatus.first }?.let {
typingStatusList.remove(it)
if (typingStatus.first != currentLoggedUsername) {
if (!typingStatusList.any { username -> username == typingStatus.first }) {
if (typingStatus.second) {
typingStatusList.add(typingStatus.first)
}
} else {
typingStatusList.find { username -> username == typingStatus.first }?.let {
typingStatusList.remove(it)
if (typingStatus.second) {
typingStatusList.add(typingStatus.first)
}
}
}
if (typingStatusList.isNotEmpty()) {
view.showTypingStatus(typingStatusList.toList())
} else {
view.hideTypingStatusView()
}
}
if (typingStatusList.isNotEmpty()) {
view.showTypingStatus(typingStatusList.toList()) // copy typingStatusList
} else {
view.hideTypingStatusView()
}
}
......
......@@ -126,7 +126,8 @@ internal const val MENU_ACTION_PINNED_MESSAGES = 4
internal const val MENU_ACTION_FAVORITE_MESSAGES = 5
internal const val MENU_ACTION_FILES = 6
class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiReactionListener {
class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiReactionListener,
ChatRoomAdapter.OnActionSelected {
@Inject
lateinit var presenter: ChatRoomPresenter
@Inject
......@@ -200,6 +201,9 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
} else {
requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" }
}
adapter = ChatRoomAdapter(chatRoomType, chatRoomName, this,
reactionListener = this)
}
override fun onCreateView(
......@@ -335,13 +339,6 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
if (recycler_view.adapter == null) {
adapter = ChatRoomAdapter(
chatRoomType,
chatRoomName,
presenter,
reactionListener = this@ChatRoomFragment,
context = context
)
recycler_view.adapter = adapter
if (dataSet.size >= 30) {
recycler_view.addOnScrollListener(endlessRecyclerViewScrollListener)
......@@ -967,4 +964,55 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
private fun setupToolbar(toolbarTitle: String) {
(activity as ChatRoomActivity).showToolbarTitle(toolbarTitle)
}
override fun showMessageInfo(id: String) {
presenter.messageInfo(id)
}
override fun citeMessage(roomName: String, roomType: String, messageId: String, mentionAuthor: Boolean) {
presenter.citeMessage(roomName, roomType, messageId, mentionAuthor)
}
override fun copyMessage(id: String) {
presenter.copyMessage(id)
}
override fun editMessage(roomId: String, messageId: String, text: String) {
presenter.editMessage(roomId, messageId, text)
}
override fun toogleStar(id: String, star: Boolean) {
if (star) {
presenter.starMessage(id)
} else {
presenter.unstarMessage(id)
}
}
override fun tooglePin(id: String, pin: Boolean) {
if (pin) {
presenter.pinMessage(id)
} else {
presenter.unpinMessage(id)
}
}
override fun deleteMessage(roomId: String, id: String) {
ui {
val builder = AlertDialog.Builder(it)
builder.setTitle(it.getString(R.string.msg_delete_message))
.setMessage(it.getString(R.string.msg_delete_description))
.setPositiveButton(it.getString(R.string.msg_ok)) { _, _ -> presenter.deleteMessage(roomId, id) }
.setNegativeButton(it.getString(R.string.msg_cancel)) { _, _ -> }
.show()
}
}
override fun showReactions(id: String) {
presenter.showReactions(id)
}
override fun openDirectMessage(roomName: String, message: String) {
presenter.openDirectMessage(roomName, message)
}
}
......@@ -35,7 +35,7 @@ private const val INTENT_CHAT_ROOM_ID = "chat_room_id"
class FavoriteMessagesFragment : Fragment(), FavoriteMessagesView {
private lateinit var chatRoomId: String
private lateinit var adapter: ChatRoomAdapter
private val adapter = ChatRoomAdapter(enableActions = false)
@Inject
lateinit var presenter: FavoriteMessagesPresenter
......@@ -66,7 +66,6 @@ class FavoriteMessagesFragment : Fragment(), FavoriteMessagesView {
override fun showFavoriteMessages(favoriteMessages: List<BaseUiModel<*>>) {
ui {
if (recycler_view.adapter == null) {
adapter = ChatRoomAdapter(enableActions = false)
recycler_view.adapter = adapter
val linearLayoutManager = LinearLayoutManager(context)
recycler_view.layoutManager = linearLayoutManager
......
......@@ -5,21 +5,19 @@ import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.RectF
import android.net.Uri
import androidx.core.content.res.ResourcesCompat
import android.text.Spanned
import android.text.style.ClickableSpan
import android.text.style.ReplacementSpan
import android.text.style.StyleSpan
import android.util.Patterns
import android.view.View
import androidx.core.content.res.ResourcesCompat
import chat.rocket.android.R
import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.util.extensions.openTabbedUrl
import chat.rocket.android.emoji.EmojiParser
import chat.rocket.android.emoji.EmojiRepository
import chat.rocket.android.emoji.EmojiTypefaceSpan
import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.util.extensions.openTabbedUrl
import chat.rocket.common.model.SimpleUser
import chat.rocket.core.model.Message
import org.commonmark.node.AbstractVisitor
......@@ -159,7 +157,7 @@ class MessageParser @Inject constructor(
if (node is ListItem) {
newLine()
builder.append("$number$delimiter ")
super.visit(node.firstChild as Paragraph)
super.visitChildren(node.firstChild)
newLine()
}
number++
......@@ -187,7 +185,7 @@ class MessageParser @Inject constructor(
if (!link.startsWith("@") && link !in consumed) {
builder.setSpan(object : ClickableSpan() {
override fun onClick(view: View) {
view.openTabbedUrl(getUri(link))
view.openTabbedUrl(link)
}
}, matcher.start(0), matcher.end(0))
consumed.add(link)
......@@ -195,14 +193,6 @@ class MessageParser @Inject constructor(
}
visitChildren(text)
}
private fun getUri(link: String): Uri {
val uri = Uri.parse(link)
if (uri.scheme == null) {
return Uri.parse("http://$link")
}
return uri
}
}
class MentionSpan(
......
......@@ -5,6 +5,7 @@ import chat.rocket.android.db.DatabaseManagerFactory
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.main.uimodel.NavHeaderUiModel
import chat.rocket.android.main.uimodel.NavHeaderUiModelMapper
import chat.rocket.android.push.GroupedPush
import chat.rocket.android.server.domain.GetAccountsInteractor
import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor
......@@ -52,6 +53,7 @@ class MainPresenter @Inject constructor(
private val getAccountsInteractor: GetAccountsInteractor,
private val removeAccountInteractor: RemoveAccountInteractor,
private val factory: RocketChatClientFactory,
private val groupedPush: GroupedPush,
dbManagerFactory: DatabaseManagerFactory,
getSettingsInteractor: GetSettingsInteractor,
managerFactory: ConnectionManagerFactory
......@@ -232,4 +234,12 @@ class MainPresenter @Inject constructor(
private fun updateMyself(myself: Myself) =
view.setupUserAccountInfo(navHeaderMapper.mapToUiModel(myself))
}
\ No newline at end of file
fun clearNotificationsForChatroom(chatRoomId: String?) {
if (chatRoomId == null) return
groupedPush.hostToPushMessageList[currentServer]?.let { list ->
list.removeAll { it.info.roomId == chatRoomId }
}
}
}
......@@ -5,13 +5,13 @@ import android.app.Activity
import android.app.AlertDialog
import android.app.ProgressDialog
import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import android.view.Gravity
import android.view.MenuItem
import androidx.annotation.IdRes
import androidx.appcompat.app.AppCompatActivity
import androidx.drawerlayout.widget.DrawerLayout
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import chat.rocket.android.BuildConfig
import chat.rocket.android.R
import chat.rocket.android.main.adapter.AccountsAdapter
......@@ -55,7 +55,7 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
private var expanded = false
private val headerLayout by lazy { view_navigation.getHeaderView(0) }
private var chatRoomId: String? = null
private var progressDialog : ProgressDialog? = null
private var progressDialog: ProgressDialog? = null
override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this)
......@@ -74,6 +74,9 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
chatRoomId = intent.getStringExtra(INTENT_CHAT_ROOM_ID)
println("ChatRoomId: $chatRoomId")
presenter.clearNotificationsForChatroom(chatRoomId)
presenter.connect()
presenter.loadServerAccounts()
presenter.loadCurrentInfo()
......@@ -270,4 +273,4 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
progressDialog?.dismiss()
progressDialog = null
}
}
\ No newline at end of file
}
......@@ -36,7 +36,7 @@ private const val BUNDLE_CHAT_ROOM_ID = "chat_room_id"
class MentionsFragment : Fragment(), MentionsView {
private lateinit var chatRoomId: String
private lateinit var adapter: ChatRoomAdapter
private val adapter = ChatRoomAdapter(enableActions = false)
@Inject
lateinit var presenter: MentionsPresenter
......@@ -68,7 +68,6 @@ class MentionsFragment : Fragment(), MentionsView {
override fun showMentions(mentions: List<BaseUiModel<*>>) {
ui {
if (recycler_view.adapter == null) {
adapter = ChatRoomAdapter(enableActions = false)
recycler_view.adapter = adapter
val linearLayoutManager = LinearLayoutManager(context)
......
......@@ -36,7 +36,7 @@ private const val BUNDLE_CHAT_ROOM_ID = "chat_room_id"
class PinnedMessagesFragment : Fragment(), PinnedMessagesView {
private lateinit var chatRoomId: String
private lateinit var adapter: ChatRoomAdapter
private val adapter = ChatRoomAdapter(enableActions = false)
@Inject
lateinit var presenter: PinnedMessagesPresenter
......@@ -68,7 +68,6 @@ class PinnedMessagesFragment : Fragment(), PinnedMessagesView {
override fun showPinnedMessages(pinnedMessages: List<BaseUiModel<*>>) {
ui {
if (recycler_view_pinned.adapter == null) {
adapter = ChatRoomAdapter(enableActions = false)
recycler_view_pinned.adapter = adapter
val linearLayoutManager = LinearLayoutManager(context)
......
......@@ -12,4 +12,4 @@ class GroupedPush {
// Map a hostname to a list of push messages that pertain to it.
val hostToPushMessageList = HashMap<String, MutableList<PushMessage>>()
}
\ No newline at end of file
}
......@@ -18,6 +18,7 @@ import androidx.core.app.NotificationManagerCompat
import androidx.core.app.RemoteInput
import android.text.Html
import android.text.Spanned
import androidx.core.content.ContextCompat
import chat.rocket.android.R
import chat.rocket.android.main.ui.MainActivity
import chat.rocket.android.server.domain.GetAccountInteractor
......@@ -36,10 +37,6 @@ import java.util.*
import java.util.concurrent.atomic.AtomicInteger
import javax.inject.Inject
/**
* Refer to: https://github.com/RocketChat/Rocket.Chat.Android/blob/9e846b7fde8fe0c74b9e0117c37ce49293308db5/app/src/main/java/chat/rocket/android/push/PushManager.kt
* for old source code.
*/
class PushManager @Inject constructor(
private val groupedPushes: GroupedPush,
private val manager: NotificationManager,
......@@ -80,7 +77,7 @@ class PushManager @Inject constructor(
showNotification(pushMessage)
} catch (ex: Exception) {
Timber.d(ex, "Error parsing PUSH message: $data")
Timber.e(ex, "Error parsing PUSH message: $data")
ex.printStackTrace()
}
}
......@@ -101,7 +98,7 @@ class PushManager @Inject constructor(
val groupTuple = getGroupForHost(host)
groupTuple.second.incrementAndGet()
val notIdListForHostname: MutableList<PushMessage>? = groupedPushes.hostToPushMessageList.get(host)
val notIdListForHostname: MutableList<PushMessage>? = groupedPushes.hostToPushMessageList[host]
if (notIdListForHostname == null) {
groupedPushes.hostToPushMessageList[host] = arrayListOf(pushMessage)
} else {
......@@ -365,14 +362,14 @@ class PushManager @Inject constructor(
val res = context.resources
val smallIcon = res.getIdentifier(
"rocket_chat_notification", "drawable", context.packageName)
with(this, {
with(this) {
setAutoCancel(true)
setShowWhen(true)
color = context.resources.getColor(R.color.colorPrimary)
color = ContextCompat.getColor(context, R.color.colorPrimary)
setDefaults(Notification.DEFAULT_ALL)
setSmallIcon(smallIcon)
setSound(alarmSound)
})
}
return this
}
}
......
......@@ -3,6 +3,7 @@ package chat.rocket.android.util.extensions
import android.graphics.Color
import android.util.Patterns
import chat.rocket.common.model.Token
import okhttp3.HttpUrl
import timber.log.Timber
fun String.removeTrailingSlash(): String {
......@@ -64,4 +65,11 @@ fun String.parseColor(): Int {
fun String.userId(userId: String?): String? {
return userId?.let { this.replace(it, "") }
}
fun String.lowercaseUrl(): String? {
val httpUrl = HttpUrl.parse(this)
val newScheme = httpUrl?.scheme()?.toLowerCase()
return httpUrl?.newBuilder()?.scheme(newScheme)?.build()?.toString()
}
\ No newline at end of file
......@@ -7,15 +7,27 @@ import android.view.View
import chat.rocket.android.R
import timber.log.Timber
fun View.openTabbedUrl(url: Uri) {
fun View.openTabbedUrl(url: String) {
with(this) {
val uri = url.ensureScheme()
val tabsbuilder = CustomTabsIntent.Builder()
tabsbuilder.setToolbarColor(ResourcesCompat.getColor(context.resources, R.color.colorPrimary, context.theme))
val customTabsIntent = tabsbuilder.build()
try {
customTabsIntent.launchUrl(context, url)
customTabsIntent.launchUrl(context, uri)
} catch (ex: Exception) {
Timber.d(ex, "Unable to launch URL")
}
}
}
private fun String.ensureScheme(): Uri? {
// check if the URL starts with a http(s) scheme
val url = if (!this.matches(Regex("^([h|H][t|T][t|T][p|P]).*"))) {
"http://$this"
} else {
this
}
return Uri.parse(url.lowercaseUrl())
}
\ No newline at end of file
......@@ -38,7 +38,6 @@
<string name="action_invisible">Invisible</string>
<string name="action_drawing">dibujo</string>
<string name="action_save_to_gallery">Guardar en la galería</string>
<string name="action_share">Compartir</string>
<!-- Settings List -->
<string-array name="settings_actions">
......@@ -276,4 +275,5 @@
<string name="msg_file_description">Descripción del archivo</string>
<string name="msg_send">Enviar</string>
<string name="msg_sent_attachment">Envió un archivo</string>
</resources>
......@@ -18,6 +18,11 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
packagingOptions {
exclude 'META-INF/core.kotlin_module'
exclude 'META-INF/main.kotlin_module'
}
}
dependencies {
......
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