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

Merge pull request #1512 from RocketChat/beta

[RELEASE] Merge BETA into DEVELOP
parents 638759d7 7332dc06
...@@ -12,7 +12,7 @@ android { ...@@ -12,7 +12,7 @@ android {
applicationId "chat.rocket.android" applicationId "chat.rocket.android"
minSdkVersion versions.minSdk minSdkVersion versions.minSdk
targetSdkVersion versions.targetSdk targetSdkVersion versions.targetSdk
versionCode 2031 versionCode 2032
versionName "2.5.0" versionName "2.5.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true multiDexEnabled true
......
{
"formatVersion": 1,
"database": {
"version": 5,
"identityHash": "47a0c30e2696ae09bc86df16cc37279d",
"entities": [
{
"tableName": "users",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `username` TEXT, `name` TEXT, `status` TEXT NOT NULL, `utcOffset` REAL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "username",
"columnName": "username",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "status",
"columnName": "status",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "utcOffset",
"columnName": "utcOffset",
"affinity": "REAL",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": false
},
"indices": [
{
"name": "index_users_username",
"unique": false,
"columnNames": [
"username"
],
"createSql": "CREATE INDEX `index_users_username` ON `${TABLE_NAME}` (`username`)"
}
],
"foreignKeys": []
},
{
"tableName": "chatrooms",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` TEXT NOT NULL, `type` TEXT NOT NULL, `name` TEXT NOT NULL, `fullname` TEXT, `userId` TEXT, `ownerId` TEXT, `readonly` INTEGER, `isDefault` INTEGER, `favorite` INTEGER, `open` INTEGER NOT NULL, `alert` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `userMentions` INTEGER, `groupMentions` INTEGER, `updatedAt` INTEGER, `timestamp` INTEGER, `lastSeen` INTEGER, `lastMessageText` TEXT, `lastMessageUserId` TEXT, `lastMessageTimestamp` INTEGER, `broadcast` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`ownerId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`lastMessageUserId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "subscriptionId",
"columnName": "subscriptionId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "fullname",
"columnName": "fullname",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "userId",
"columnName": "userId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "ownerId",
"columnName": "ownerId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "readonly",
"columnName": "readonly",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "isDefault",
"columnName": "isDefault",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "favorite",
"columnName": "favorite",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "open",
"columnName": "open",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "alert",
"columnName": "alert",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "unread",
"columnName": "unread",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "userMentions",
"columnName": "userMentions",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "groupMentions",
"columnName": "groupMentions",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "updatedAt",
"columnName": "updatedAt",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "timestamp",
"columnName": "timestamp",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "lastSeen",
"columnName": "lastSeen",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "lastMessageText",
"columnName": "lastMessageText",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "lastMessageUserId",
"columnName": "lastMessageUserId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "lastMessageTimestamp",
"columnName": "lastMessageTimestamp",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "broadcast",
"columnName": "broadcast",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": false
},
"indices": [
{
"name": "index_chatrooms_userId",
"unique": false,
"columnNames": [
"userId"
],
"createSql": "CREATE INDEX `index_chatrooms_userId` ON `${TABLE_NAME}` (`userId`)"
},
{
"name": "index_chatrooms_ownerId",
"unique": false,
"columnNames": [
"ownerId"
],
"createSql": "CREATE INDEX `index_chatrooms_ownerId` ON `${TABLE_NAME}` (`ownerId`)"
},
{
"name": "index_chatrooms_subscriptionId",
"unique": true,
"columnNames": [
"subscriptionId"
],
"createSql": "CREATE UNIQUE INDEX `index_chatrooms_subscriptionId` ON `${TABLE_NAME}` (`subscriptionId`)"
},
{
"name": "index_chatrooms_updatedAt",
"unique": false,
"columnNames": [
"updatedAt"
],
"createSql": "CREATE INDEX `index_chatrooms_updatedAt` ON `${TABLE_NAME}` (`updatedAt`)"
},
{
"name": "index_chatrooms_lastMessageUserId",
"unique": false,
"columnNames": [
"lastMessageUserId"
],
"createSql": "CREATE INDEX `index_chatrooms_lastMessageUserId` ON `${TABLE_NAME}` (`lastMessageUserId`)"
}
],
"foreignKeys": [
{
"table": "users",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"ownerId"
],
"referencedColumns": [
"id"
]
},
{
"table": "users",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"userId"
],
"referencedColumns": [
"id"
]
},
{
"table": "users",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"lastMessageUserId"
],
"referencedColumns": [
"id"
]
}
]
}
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"47a0c30e2696ae09bc86df16cc37279d\")"
]
}
}
\ No newline at end of file
...@@ -10,6 +10,7 @@ import chat.rocket.android.chatrooms.adapter.model.RoomUiModel ...@@ -10,6 +10,7 @@ import chat.rocket.android.chatrooms.adapter.model.RoomUiModel
import chat.rocket.android.db.model.ChatRoom import chat.rocket.android.db.model.ChatRoom
import chat.rocket.android.infrastructure.LocalRepository import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.infrastructure.checkIfMyself import chat.rocket.android.infrastructure.checkIfMyself
import chat.rocket.android.server.domain.GetCurrentUserInteractor
import chat.rocket.android.server.domain.PublicSettings import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.showLastMessage import chat.rocket.android.server.domain.showLastMessage
import chat.rocket.android.server.domain.useRealName import chat.rocket.android.server.domain.useRealName
...@@ -27,7 +28,7 @@ import chat.rocket.core.model.SpotlightResult ...@@ -27,7 +28,7 @@ import chat.rocket.core.model.SpotlightResult
class RoomUiModelMapper( class RoomUiModelMapper(
private val context: Application, private val context: Application,
private val settings: PublicSettings, private val settings: PublicSettings,
private val localRepository: LocalRepository, private val userInteractor: GetCurrentUserInteractor,
private val serverUrl: String private val serverUrl: String
) { ) {
private val nameUnreadColor = ContextCompat.getColor(context, R.color.colorPrimaryText) private val nameUnreadColor = ContextCompat.getColor(context, R.color.colorPrimaryText)
...@@ -37,6 +38,10 @@ class RoomUiModelMapper( ...@@ -37,6 +38,10 @@ class RoomUiModelMapper(
private val messageUnreadColor = ContextCompat.getColor(context, android.R.color.primary_text_light) private val messageUnreadColor = ContextCompat.getColor(context, android.R.color.primary_text_light)
private val messageColor = ContextCompat.getColor(context, R.color.colorSecondaryText) private val messageColor = ContextCompat.getColor(context, R.color.colorSecondaryText)
private val currentUser by lazy {
userInteractor.get()
}
fun map(rooms: List<ChatRoom>, grouped: Boolean = false): List<ItemHolder<*>> { fun map(rooms: List<ChatRoom>, grouped: Boolean = false): List<ItemHolder<*>> {
val list = ArrayList<ItemHolder<*>>(rooms.size + 4) val list = ArrayList<ItemHolder<*>>(rooms.size + 4)
var lastType: String? = null var lastType: String? = null
...@@ -88,8 +93,9 @@ class RoomUiModelMapper( ...@@ -88,8 +93,9 @@ class RoomUiModelMapper(
name = name!!, name = name!!,
type = type, type = type,
avatar = serverUrl.avatarUrl(name!!, isGroupOrChannel = true), avatar = serverUrl.avatarUrl(name!!, isGroupOrChannel = true),
lastMessage = mapLastMessage(lastMessage?.sender?.username, lastMessage = mapLastMessage(lastMessage?.sender?.id, lastMessage?.sender?.username,
lastMessage?.sender?.name, lastMessage?.message) lastMessage?.sender?.name, lastMessage?.message,
isDirectMessage = type is RoomType.DirectMessage)
) )
} }
} }
...@@ -107,14 +113,17 @@ class RoomUiModelMapper( ...@@ -107,14 +113,17 @@ class RoomUiModelMapper(
serverUrl.avatarUrl(name, isGroupOrChannel = true) serverUrl.avatarUrl(name, isGroupOrChannel = true)
} }
val unread = mapUnread(unread) val unread = mapUnread(unread)
val lastMessage = mapLastMessage(chatRoom.lastMessageUserName, val lastMessage = mapLastMessage(lastMessageUserId, chatRoom.lastMessageUserName,
chatRoom.lastMessageUserFullName, lastMessageText, isUnread) chatRoom.lastMessageUserFullName, lastMessageText, isUnread,
type is RoomType.DirectMessage)
val open = open
RoomUiModel( RoomUiModel(
id = id, id = id,
name = roomName, name = roomName,
type = type, type = type,
avatar = avatar, avatar = avatar,
open = open,
date = timestamp, date = timestamp,
unread = unread, unread = unread,
alert = isUnread, alert = isUnread,
...@@ -136,14 +145,16 @@ class RoomUiModelMapper( ...@@ -136,14 +145,16 @@ class RoomUiModelMapper(
} }
} }
private fun mapLastMessage(name: String?, fullName: String?, text: String?, unread: Boolean = false): CharSequence? { private fun mapLastMessage(userId: String?, name: String?, fullName: String?, text: String?,
unread: Boolean = false,
isDirectMessage: Boolean = false): CharSequence? {
return if (!settings.showLastMessage()) { return if (!settings.showLastMessage()) {
null null
} else if (name != null && text != null) { } else if (name != null && text != null) {
val user = if (localRepository.checkIfMyself(name)) { val user = if (currentUser != null && currentUser!!.id == userId) {
"${context.getString(R.string.msg_you)}: " "${context.getString(R.string.msg_you)}: "
} else { } else {
"${mapName(name, fullName, unread)}: " if (isDirectMessage) "" else "${mapName(name, fullName, unread)}: "
} }
val color = if (unread) messageUnreadColor else messageColor val color = if (unread) messageUnreadColor else messageColor
......
...@@ -8,6 +8,7 @@ data class RoomUiModel( ...@@ -8,6 +8,7 @@ data class RoomUiModel(
val type: RoomType, val type: RoomType,
val name: CharSequence, val name: CharSequence,
val avatar: String, val avatar: String,
val open: Boolean = false,
val date: CharSequence? = null, val date: CharSequence? = null,
val unread: String? = null, val unread: String? = null,
val alert: Boolean = false, val alert: Boolean = false,
......
...@@ -9,9 +9,12 @@ import chat.rocket.android.chatrooms.ui.ChatRoomsFragment ...@@ -9,9 +9,12 @@ import chat.rocket.android.chatrooms.ui.ChatRoomsFragment
import chat.rocket.android.dagger.scope.PerFragment import chat.rocket.android.dagger.scope.PerFragment
import chat.rocket.android.db.ChatRoomDao import chat.rocket.android.db.ChatRoomDao
import chat.rocket.android.db.DatabaseManager import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.db.UserDao
import chat.rocket.android.infrastructure.LocalRepository import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.server.domain.GetCurrentUserInteractor
import chat.rocket.android.server.domain.PublicSettings import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.SettingsRepository import chat.rocket.android.server.domain.SettingsRepository
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.infraestructure.ConnectionManager import chat.rocket.android.server.infraestructure.ConnectionManager
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infraestructure.RocketChatClientFactory
...@@ -48,6 +51,10 @@ class ChatRoomsFragmentModule { ...@@ -48,6 +51,10 @@ class ChatRoomsFragmentModule {
@PerFragment @PerFragment
fun provideChatRoomDao(manager: DatabaseManager): ChatRoomDao = manager.chatRoomDao() fun provideChatRoomDao(manager: DatabaseManager): ChatRoomDao = manager.chatRoomDao()
@Provides
@PerFragment
fun provideUserDao(manager: DatabaseManager): UserDao = manager.userDao()
@Provides @Provides
@PerFragment @PerFragment
fun provideConnectionManager( fun provideConnectionManager(
...@@ -80,9 +87,19 @@ class ChatRoomsFragmentModule { ...@@ -80,9 +87,19 @@ class ChatRoomsFragmentModule {
fun provideRoomMapper( fun provideRoomMapper(
context: Application, context: Application,
repository: SettingsRepository, repository: SettingsRepository,
localRepository: LocalRepository, userInteractor: GetCurrentUserInteractor,
@Named("currentServer") serverUrl: String @Named("currentServer") serverUrl: String
): RoomUiModelMapper { ): RoomUiModelMapper {
return RoomUiModelMapper(context, repository.get(serverUrl), localRepository, serverUrl) return RoomUiModelMapper(context, repository.get(serverUrl), userInteractor, serverUrl)
}
@Provides
@PerFragment
fun provideGetCurrentUserInteractor(
tokenRepository: TokenRepository,
@Named("currentServer") serverUrl: String,
userDao: UserDao
): GetCurrentUserInteractor {
return GetCurrentUserInteractor(tokenRepository, serverUrl, userDao)
} }
} }
\ No newline at end of file
...@@ -3,7 +3,6 @@ package chat.rocket.android.chatrooms.domain ...@@ -3,7 +3,6 @@ package chat.rocket.android.chatrooms.domain
import chat.rocket.android.db.DatabaseManager import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.db.model.ChatRoomEntity import chat.rocket.android.db.model.ChatRoomEntity
import chat.rocket.android.db.model.UserEntity import chat.rocket.android.db.model.UserEntity
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.util.retryIO import chat.rocket.android.util.retryIO
import chat.rocket.core.RocketChatClient import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.rest.chatRooms import chat.rocket.core.internal.rest.chatRooms
...@@ -19,60 +18,10 @@ class FetchChatRoomsInteractor( ...@@ -19,60 +18,10 @@ class FetchChatRoomsInteractor(
suspend fun refreshChatRooms() { suspend fun refreshChatRooms() {
val rooms = retryIO("fetch chatRooms", times = 10, val rooms = retryIO("fetch chatRooms", times = 10,
initialDelay = 200, maxDelay = 2000) { initialDelay = 200, maxDelay = 2000) {
client.chatRooms().update.map { room -> client.chatRooms().update
mapChatRoom(room)
}
} }
Timber.d("Refreshing rooms: $rooms") Timber.d("Refreshing rooms: $rooms")
dbManager.insert(rooms) dbManager.processRooms(rooms)
}
private suspend fun mapChatRoom(room: ChatRoom): ChatRoomEntity {
with(room) {
val userId = userId()
if (userId != null && dbManager.findUser(userId) == null) {
Timber.d("Missing user, inserting: $userId")
dbManager.insert(UserEntity(userId))
}
lastMessage?.sender?.let { user ->
user.id?.let { id ->
if (dbManager.findUser(id) == null) {
Timber.d("Missing last message user, inserting: $id")
dbManager.insert(UserEntity(id, user.username, user.name))
}
}
}
user?.id?.let { id ->
if (dbManager.findUser(id) == null) {
Timber.d("Missing owner user, inserting: $id")
dbManager.insert(UserEntity(id, user?.username, user?.name))
}
}
return ChatRoomEntity(
id = id,
subscriptionId = subscriptionId,
type = type.toString(),
name = name,
fullname = fullName,
userId = userId,
ownerId = user?.id,
readonly = readonly,
isDefault = default,
favorite = favorite,
open = open,
alert = alert,
unread = unread,
userMentions = userMentions,
groupMentions = groupMentions,
updatedAt = updatedAt,
timestamp = timestamp,
lastSeen = lastSeen,
lastMessageText = lastMessage?.message,
lastMessageUserId = lastMessage?.sender?.id,
lastMessageTimestamp = lastMessage?.timestamp,
broadcast = broadcast
)
}
} }
} }
\ No newline at end of file
...@@ -9,8 +9,8 @@ import chat.rocket.android.helper.UserHelper ...@@ -9,8 +9,8 @@ import chat.rocket.android.helper.UserHelper
import chat.rocket.android.infrastructure.LocalRepository 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.SettingsRepository import chat.rocket.android.server.domain.SettingsRepository
import chat.rocket.android.server.domain.useSpecialCharsOnRoom
import chat.rocket.android.server.domain.useRealName import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.server.domain.useSpecialCharsOnRoom
import chat.rocket.android.server.infraestructure.ConnectionManager import chat.rocket.android.server.infraestructure.ConnectionManager
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.retryIO import chat.rocket.android.util.retryIO
...@@ -20,9 +20,12 @@ import chat.rocket.common.model.User ...@@ -20,9 +20,12 @@ import chat.rocket.common.model.User
import chat.rocket.common.model.roomTypeOf import chat.rocket.common.model.roomTypeOf
import chat.rocket.core.internal.realtime.createDirectMessage import chat.rocket.core.internal.realtime.createDirectMessage
import chat.rocket.core.internal.rest.me import chat.rocket.core.internal.rest.me
import chat.rocket.core.internal.rest.show
import kotlinx.coroutines.experimental.withTimeout
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Named import javax.inject.Named
import kotlin.coroutines.experimental.suspendCoroutine
class ChatRoomsPresenter @Inject constructor( class ChatRoomsPresenter @Inject constructor(
private val view: ChatRoomsView, private val view: ChatRoomsView,
...@@ -44,7 +47,7 @@ class ChatRoomsPresenter @Inject constructor( ...@@ -44,7 +47,7 @@ class ChatRoomsPresenter @Inject constructor(
try { try {
val room = dbManager.getRoom(chatRoom.id) val room = dbManager.getRoom(chatRoom.id)
if (room != null) { if (room != null) {
loadChatRoom(room.chatRoom) loadChatRoom(room.chatRoom, true)
} else { } else {
with(chatRoom) { with(chatRoom) {
val entity = ChatRoomEntity( val entity = ChatRoomEntity(
...@@ -53,44 +56,56 @@ class ChatRoomsPresenter @Inject constructor( ...@@ -53,44 +56,56 @@ class ChatRoomsPresenter @Inject constructor(
type = type.toString(), type = type.toString(),
name = username ?: name.toString(), name = username ?: name.toString(),
fullname = name.toString(), fullname = name.toString(),
open = false open = open
) )
loadChatRoom(entity) loadChatRoom(entity, false)
} }
} }
} catch (ex: Exception) {
Timber.d(ex, "Error loading channel")
view.showGenericErrorMessage()
} finally { } finally {
view.hideLoadingRoom() view.hideLoadingRoom()
} }
} }
} }
fun loadChatRoom(chatRoom: ChatRoomEntity) { suspend fun loadChatRoom(chatRoom: ChatRoomEntity, local: Boolean = false) {
with(chatRoom) { with(chatRoom) {
val isDirectMessage = roomTypeOf(type) is RoomType.DirectMessage val isDirectMessage = roomTypeOf(type) is RoomType.DirectMessage
val roomName = if (settings.useSpecialCharsOnRoom() || (isDirectMessage && settings.useRealName())) { val roomName = if (settings.useSpecialCharsOnRoom() || (isDirectMessage && settings.useRealName())) {
fullname ?: name fullname ?: name
} else { } else {
name name
} }
launchUI(strategy) { val myself = getCurrentUser()
val myself = getCurrentUser() if (myself?.username == null) {
if (myself?.username == null) { view.showMessage(R.string.msg_generic_error)
view.showMessage(R.string.msg_generic_error) } else {
} else { val id = if (isDirectMessage && !open) {
val id = if (isDirectMessage && !open) { // If from local database, we already have the roomId, no need to concatenate
if (local) {
retryIO {
client.show(id, roomTypeOf(RoomType.DIRECT_MESSAGE))
}
id
} else {
retryIO("createDirectMessage($name)") { retryIO("createDirectMessage($name)") {
client.createDirectMessage(name) withTimeout(10000) {
createDirectMessage(name)
}
} }
val fromTo = mutableListOf(myself.id, id).apply { val fromTo = mutableListOf(myself.id, id).apply {
sort() sort()
} }
fromTo.joinToString("") fromTo.joinToString("")
} else {
id
} }
} else {
id
}
navigator.toChatRoom( navigator.toChatRoom(
chatRoomId = id, chatRoomId = id,
chatRoomName = roomName, chatRoomName = roomName,
chatRoomType = type, chatRoomType = type,
...@@ -99,8 +114,7 @@ class ChatRoomsPresenter @Inject constructor( ...@@ -99,8 +114,7 @@ class ChatRoomsPresenter @Inject constructor(
isSubscribed = open, isSubscribed = open,
isCreator = ownerId == myself.id || isDirectMessage, isCreator = ownerId == myself.id || isDirectMessage,
isFavorite = favorite ?: false isFavorite = favorite ?: false
) )
}
} }
} }
} }
...@@ -126,4 +140,10 @@ class ChatRoomsPresenter @Inject constructor( ...@@ -126,4 +140,10 @@ class ChatRoomsPresenter @Inject constructor(
} }
return null return null
} }
private suspend fun createDirectMessage(name: String): Boolean = suspendCoroutine { cont ->
client.createDirectMessage(name) { success, _ ->
cont.resume(success)
}
}
} }
\ No newline at end of file
...@@ -21,19 +21,23 @@ abstract class ChatRoomDao : BaseDao<ChatRoomEntity> { ...@@ -21,19 +21,23 @@ abstract class ChatRoomDao : BaseDao<ChatRoomEntity> {
abstract fun get(id: String): ChatRoom? abstract fun get(id: String): ChatRoom?
@Transaction @Transaction
@Query("$BASE_QUERY") @Query("$BASE_QUERY $FILTER_NOT_OPENED")
abstract fun getAllSync(): List<ChatRoom> abstract fun getAllSync(): List<ChatRoom>
@Transaction @Transaction
@Query("""$BASE_QUERY WHERE chatrooms.name LIKE '%' || :query || '%' OR users.name LIKE '%' || :query || '%'""") @Query("""$BASE_QUERY
WHERE chatrooms.name LIKE '%' || :query || '%'
OR users.name LIKE '%' || :query || '%'
""")
abstract fun searchSync(query: String): List<ChatRoom> abstract fun searchSync(query: String): List<ChatRoom>
@Query("SELECT COUNT(id) FROM chatrooms") @Query("SELECT COUNT(id) FROM chatrooms WHERE open = 1")
abstract fun count(): Long abstract fun count(): Long
@Transaction @Transaction
@Query(""" @Query("""
$BASE_QUERY $BASE_QUERY
$FILTER_NOT_OPENED
ORDER BY ORDER BY
CASE CASE
WHEN lastMessageTimeStamp IS NOT NULL THEN lastMessageTimeStamp WHEN lastMessageTimeStamp IS NOT NULL THEN lastMessageTimeStamp
...@@ -45,6 +49,7 @@ abstract class ChatRoomDao : BaseDao<ChatRoomEntity> { ...@@ -45,6 +49,7 @@ abstract class ChatRoomDao : BaseDao<ChatRoomEntity> {
@Transaction @Transaction
@Query(""" @Query("""
$BASE_QUERY $BASE_QUERY
$FILTER_NOT_OPENED
ORDER BY ORDER BY
$TYPE_ORDER, $TYPE_ORDER,
CASE CASE
...@@ -57,6 +62,7 @@ abstract class ChatRoomDao : BaseDao<ChatRoomEntity> { ...@@ -57,6 +62,7 @@ abstract class ChatRoomDao : BaseDao<ChatRoomEntity> {
@Transaction @Transaction
@Query(""" @Query("""
$BASE_QUERY $BASE_QUERY
$FILTER_NOT_OPENED
ORDER BY name ORDER BY name
""") """)
abstract fun getAllAlphabetically(): LiveData<List<ChatRoom>> abstract fun getAllAlphabetically(): LiveData<List<ChatRoom>>
...@@ -64,6 +70,7 @@ abstract class ChatRoomDao : BaseDao<ChatRoomEntity> { ...@@ -64,6 +70,7 @@ abstract class ChatRoomDao : BaseDao<ChatRoomEntity> {
@Transaction @Transaction
@Query(""" @Query("""
$BASE_QUERY $BASE_QUERY
$FILTER_NOT_OPENED
ORDER BY ORDER BY
$TYPE_ORDER, $TYPE_ORDER,
name name
...@@ -113,6 +120,10 @@ abstract class ChatRoomDao : BaseDao<ChatRoomEntity> { ...@@ -113,6 +120,10 @@ abstract class ChatRoomDao : BaseDao<ChatRoomEntity> {
LEFT JOIN users AS lmUsers ON chatrooms.lastMessageUserId = lmUsers.id LEFT JOIN users AS lmUsers ON chatrooms.lastMessageUserId = lmUsers.id
""" """
const val FILTER_NOT_OPENED = """
WHERE chatrooms.open = 1
"""
const val TYPE_ORDER = """ const val TYPE_ORDER = """
CASE CASE
WHEN type = 'c' THEN 1 WHEN type = 'c' THEN 1
......
...@@ -2,16 +2,29 @@ package chat.rocket.android.db ...@@ -2,16 +2,29 @@ package chat.rocket.android.db
import androidx.room.Database import androidx.room.Database
import androidx.room.RoomDatabase import androidx.room.RoomDatabase
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import chat.rocket.android.db.model.ChatRoomEntity import chat.rocket.android.db.model.ChatRoomEntity
import chat.rocket.android.db.model.UserEntity import chat.rocket.android.db.model.UserEntity
@Database( @Database(
entities = [UserEntity::class, ChatRoomEntity::class], entities = [UserEntity::class, ChatRoomEntity::class],
version = 4, version = 5,
exportSchema = true exportSchema = true
) )
abstract class RCDatabase : RoomDatabase() { abstract class RCDatabase : RoomDatabase() {
abstract fun userDao(): UserDao abstract fun userDao(): UserDao
abstract fun chatRoomDao(): ChatRoomDao abstract fun chatRoomDao(): ChatRoomDao
companion object {
@JvmField
val MIGRATION_4_5 = Migration4to5()
}
}
class Migration4to5 : Migration(4, 5) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("CREATE INDEX `index_chatrooms_lastMessageUserId` ON `chatrooms` (`lastMessageUserId`)")
}
} }
\ No newline at end of file
...@@ -13,6 +13,12 @@ import timber.log.Timber ...@@ -13,6 +13,12 @@ import timber.log.Timber
@Dao @Dao
abstract class UserDao : BaseDao<UserEntity> { abstract class UserDao : BaseDao<UserEntity> {
@Query("""
UPDATE users set STATUS = "offline"
""")
abstract fun clearStatus()
@Update(onConflict = OnConflictStrategy.IGNORE) @Update(onConflict = OnConflictStrategy.IGNORE)
abstract fun update(user: UserEntity): Int abstract fun update(user: UserEntity): Int
...@@ -22,6 +28,9 @@ abstract class UserDao : BaseDao<UserEntity> { ...@@ -22,6 +28,9 @@ abstract class UserDao : BaseDao<UserEntity> {
@Query("SELECT id FROM users WHERE ID = :id") @Query("SELECT id FROM users WHERE ID = :id")
abstract fun findUser(id: String): String? abstract fun findUser(id: String): String?
@Query("SELECT * FROM users WHERE ID = :id")
abstract fun getUser(id:String): UserEntity?
@Transaction @Transaction
open fun upsert(user: BaseUserEntity) { open fun upsert(user: BaseUserEntity) {
internalUpsert(user) internalUpsert(user)
......
...@@ -11,7 +11,8 @@ import androidx.room.PrimaryKey ...@@ -11,7 +11,8 @@ import androidx.room.PrimaryKey
Index(value = ["userId"]), Index(value = ["userId"]),
Index(value = ["ownerId"]), Index(value = ["ownerId"]),
Index(value = ["subscriptionId"], unique = true), Index(value = ["subscriptionId"], unique = true),
Index(value = ["updatedAt"]) Index(value = ["updatedAt"]),
Index(value = ["lastMessageUserId"])
], ],
foreignKeys = [ foreignKeys = [
ForeignKey(entity = UserEntity::class, parentColumns = ["id"], childColumns = ["ownerId"]), ForeignKey(entity = UserEntity::class, parentColumns = ["id"], childColumns = ["ownerId"]),
...@@ -19,7 +20,6 @@ import androidx.room.PrimaryKey ...@@ -19,7 +20,6 @@ import androidx.room.PrimaryKey
ForeignKey(entity = UserEntity::class, parentColumns = ["id"], childColumns = ["lastMessageUserId"]) ForeignKey(entity = UserEntity::class, parentColumns = ["id"], childColumns = ["lastMessageUserId"])
] ]
) )
data class ChatRoomEntity( data class ChatRoomEntity(
@PrimaryKey var id: String, @PrimaryKey var id: String,
var subscriptionId: String, var subscriptionId: String,
......
...@@ -32,5 +32,6 @@ interface LocalRepository { ...@@ -32,5 +32,6 @@ interface LocalRepository {
} }
} }
// FIXME - we are saving the user full name here when the server is UI_Use_Real_Name true
fun LocalRepository.checkIfMyself(username: String) = username() == username fun LocalRepository.checkIfMyself(username: String) = username() == username
fun LocalRepository.username() = get(LocalRepository.CURRENT_USERNAME_KEY) fun LocalRepository.username() = get(LocalRepository.CURRENT_USERNAME_KEY)
\ No newline at end of file
...@@ -9,6 +9,7 @@ import chat.rocket.android.server.domain.GetAccountsInteractor ...@@ -9,6 +9,7 @@ import chat.rocket.android.server.domain.GetAccountsInteractor
import chat.rocket.android.server.domain.GetCurrentServerInteractor import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.PublicSettings import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.RefreshSettingsInteractor
import chat.rocket.android.server.domain.RemoveAccountInteractor import chat.rocket.android.server.domain.RemoveAccountInteractor
import chat.rocket.android.server.domain.SaveAccountInteractor import chat.rocket.android.server.domain.SaveAccountInteractor
import chat.rocket.android.server.domain.TokenRepository import chat.rocket.android.server.domain.TokenRepository
...@@ -33,6 +34,7 @@ import chat.rocket.core.internal.rest.unregisterPushToken ...@@ -33,6 +34,7 @@ import chat.rocket.core.internal.rest.unregisterPushToken
import chat.rocket.core.model.Myself import chat.rocket.core.model.Myself
import kotlinx.coroutines.experimental.CommonPool import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.channels.Channel import kotlinx.coroutines.experimental.channels.Channel
import kotlinx.coroutines.experimental.launch
import kotlinx.coroutines.experimental.withContext import kotlinx.coroutines.experimental.withContext
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
...@@ -43,6 +45,7 @@ class MainPresenter @Inject constructor( ...@@ -43,6 +45,7 @@ class MainPresenter @Inject constructor(
private val navigator: MainNavigator, private val navigator: MainNavigator,
private val tokenRepository: TokenRepository, private val tokenRepository: TokenRepository,
private val serverInteractor: GetCurrentServerInteractor, private val serverInteractor: GetCurrentServerInteractor,
private val refreshSettingsInteractor: RefreshSettingsInteractor,
private val localRepository: LocalRepository, private val localRepository: LocalRepository,
private val navHeaderMapper: NavHeaderUiModelMapper, private val navHeaderMapper: NavHeaderUiModelMapper,
private val saveAccountInteractor: SaveAccountInteractor, private val saveAccountInteractor: SaveAccountInteractor,
...@@ -149,6 +152,7 @@ class MainPresenter @Inject constructor( ...@@ -149,6 +152,7 @@ class MainPresenter @Inject constructor(
} }
fun connect() { fun connect() {
launch { refreshSettingsInteractor.refresh(currentServer) }
manager.connect() manager.connect()
} }
......
...@@ -14,6 +14,7 @@ import chat.rocket.android.profile.presentation.ProfileView ...@@ -14,6 +14,7 @@ import chat.rocket.android.profile.presentation.ProfileView
import chat.rocket.android.util.extension.asObservable import chat.rocket.android.util.extension.asObservable
import chat.rocket.android.util.extensions.* import chat.rocket.android.util.extensions.*
import dagger.android.support.AndroidSupportInjection import dagger.android.support.AndroidSupportInjection
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable import io.reactivex.disposables.Disposable
import io.reactivex.rxkotlin.Observables import io.reactivex.rxkotlin.Observables
import kotlinx.android.synthetic.main.avatar_profile.* import kotlinx.android.synthetic.main.avatar_profile.*
...@@ -28,7 +29,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback { ...@@ -28,7 +29,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
private lateinit var currentEmail: String private lateinit var currentEmail: String
private lateinit var currentAvatar: String private lateinit var currentAvatar: String
private var actionMode: ActionMode? = null private var actionMode: ActionMode? = null
private lateinit var editTextsDisposable: Disposable private val editTextsDisposable = CompositeDisposable()
companion object { companion object {
fun newInstance() = ProfileFragment() fun newInstance() = ProfileFragment()
...@@ -170,7 +171,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback { ...@@ -170,7 +171,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
} }
private fun subscribeEditTexts() { private fun subscribeEditTexts() {
editTextsDisposable = Observables.combineLatest( editTextsDisposable.add(Observables.combineLatest(
text_name.asObservable(), text_name.asObservable(),
text_username.asObservable(), text_username.asObservable(),
text_email.asObservable(), text_email.asObservable(),
...@@ -186,11 +187,11 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback { ...@@ -186,11 +187,11 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
} else { } else {
finishActionMode() finishActionMode()
} }
} })
} }
private fun unsubscribeEditTexts() { private fun unsubscribeEditTexts() {
editTextsDisposable.dispose() editTextsDisposable.clear()
} }
private fun startActionMode() { private fun startActionMode() {
......
package chat.rocket.android.server.domain
import chat.rocket.android.db.UserDao
import chat.rocket.android.db.model.UserEntity
class GetCurrentUserInteractor(
private val tokenRepository: TokenRepository,
private val currentServer: String,
private val userDao: UserDao
) {
fun get(): UserEntity? {
return tokenRepository.get(currentServer)?.let {
userDao.getUser(it.userId)
}
}
}
...@@ -71,6 +71,7 @@ class ConnectionManager( ...@@ -71,6 +71,7 @@ class ConnectionManager(
Timber.d("Changing status to: $status") Timber.d("Changing status to: $status")
when (status) { when (status) {
is State.Connected -> { is State.Connected -> {
dbManager.clearUsersStatus()
client.subscribeSubscriptions { _, id -> client.subscribeSubscriptions { _, id ->
Timber.d("Subscribed to subscriptions: $id") Timber.d("Subscribed to subscriptions: $id")
subscriptionId = id subscriptionId = id
...@@ -149,7 +150,7 @@ class ConnectionManager( ...@@ -149,7 +150,7 @@ class ConnectionManager(
launch(parent = connectJob) { launch(parent = connectJob) {
for (myself in client.userDataChannel) { for (myself in client.userDataChannel) {
Timber.d("Got userData") Timber.d("Got userData")
userActor.send(myself.asUser()) dbManager.updateSelfUser(myself)
for (channel in userDataChannels) { for (channel in userDataChannels) {
channel.send(myself) channel.send(myself)
} }
...@@ -260,10 +261,6 @@ class ConnectionManager( ...@@ -260,10 +261,6 @@ class ConnectionManager(
} }
} }
private fun Myself.asUser(): User {
return User(id, name, username, status, utcOffset, null, roles)
}
private fun Long.orZero(): Long { private fun Long.orZero(): Long {
return if (this < 0) 0 else this return if (this < 0) 0 else this
} }
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<android.support.constraint.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/layout_container" android:id="@+id/layout_container"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolbar_layout"> app:layout_constraintTop_toBottomOf="@id/toolbar_layout">
<android.support.design.chip.ChipGroup <com.google.android.material.chip.ChipGroup
android:id="@+id/members_chips" android:id="@+id/members_chips"
style="@style/Widget.MaterialComponents.Chip.Entry" style="@style/Widget.MaterialComponents.Chip.Entry"
android:layout_width="match_parent" android:layout_width="match_parent"
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"> app:layout_constraintTop_toTopOf="parent">
</android.support.design.chip.ChipGroup> </com.google.android.material.chip.ChipGroup>
<com.wang.avi.AVLoadingIndicatorView <com.wang.avi.AVLoadingIndicatorView
android:id="@+id/view_loading" android:id="@+id/view_loading"
...@@ -63,12 +63,12 @@ ...@@ -63,12 +63,12 @@
android:background="@color/colorDividerMessageComposer" android:background="@color/colorDividerMessageComposer"
app:layout_constraintTop_toBottomOf="@id/text_search_member" /> app:layout_constraintTop_toBottomOf="@id/text_search_member" />
<android.support.v7.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view" android:id="@+id/recycler_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:scrollbars="vertical" android:scrollbars="vertical"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/separator_1" /> app:layout_constraintTop_toBottomOf="@id/separator_1" />
</android.support.constraint.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</android.support.constraint.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file \ No newline at end of file
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
...@@ -41,4 +41,4 @@ ...@@ -41,4 +41,4 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:text="04/06/2018 14:18:36" /> tools:text="04/06/2018 14:18:36" />
</android.support.constraint.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/toolbar_container" android:id="@+id/toolbar_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<android.support.v7.widget.Toolbar <androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar" android:id="@+id/toolbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_height" android:layout_height="@dimen/toolbar_height"
...@@ -29,6 +29,6 @@ ...@@ -29,6 +29,6 @@
android:gravity="end" android:gravity="end"
android:textSize="14sp" /> android:textSize="14sp" />
</android.support.v7.widget.Toolbar> </androidx.appcompat.widget.Toolbar>
</android.support.constraint.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file \ No newline at end of file
...@@ -265,4 +265,5 @@ ...@@ -265,4 +265,5 @@
<string name="read_by">Leído por</string> <string name="read_by">Leído por</string>
<string name="message_information_title">Información del mensaje</string> <string name="message_information_title">Información del mensaje</string>
<string name="msg_log_out">Saliendo de tu cuenta…</string> <string name="msg_log_out">Saliendo de tu cuenta…</string>
<string name="msg_sent_attachment">Envió un archivo</string>
</resources> </resources>
...@@ -293,4 +293,5 @@ ...@@ -293,4 +293,5 @@
<string name="read_by">Lire par</string> <string name="read_by">Lire par</string>
<string name="message_information_title">Informations sur le message</string> <string name="message_information_title">Informations sur le message</string>
<string name="msg_log_out">Déconnecter…</string> <string name="msg_log_out">Déconnecter…</string>
<string name="msg_sent_attachment">Envoyé un fichier</string>
</resources> </resources>
...@@ -272,4 +272,5 @@ ...@@ -272,4 +272,5 @@
<string name="read_by">Lida por</string> <string name="read_by">Lida por</string>
<string name="message_information_title">Informações da mensagem</string> <string name="message_information_title">Informações da mensagem</string>
<string name="msg_log_out">Deslogando…</string> <string name="msg_log_out">Deslogando…</string>
<string name="msg_sent_attachment">Enviou um arquivo</string>
</resources> </resources>
...@@ -124,6 +124,7 @@ ...@@ -124,6 +124,7 @@
<string name="msg_upload_file">Upload file</string> <string name="msg_upload_file">Upload file</string>
<string name="msg_file_description">File description</string> <string name="msg_file_description">File description</string>
<string name="msg_send">Send</string> <string name="msg_send">Send</string>
<string name="msg_sent_attachment">Sent an attachment</string>
<!-- Create channel messages --> <!-- Create channel messages -->
<string name="msg_private_channel">Private</string> <string name="msg_private_channel">Private</string>
......
...@@ -5,8 +5,8 @@ buildscript { ...@@ -5,8 +5,8 @@ buildscript {
repositories { repositories {
google() google()
jcenter() jcenter()
mavenCentral()
maven { url 'https://maven.fabric.io/public' } maven { url 'https://maven.fabric.io/public' }
mavenCentral()
} }
dependencies { dependencies {
......
...@@ -24,9 +24,9 @@ ext { ...@@ -24,9 +24,9 @@ ext {
playServices : '15.0.0', playServices : '15.0.0',
exoPlayer : '2.6.0', exoPlayer : '2.6.0',
flexbox : '0.3.2', flexbox : '0.3.2',
material : '1.0.0-alpha1', material : '1.0.0-beta01',
room : '2.0.0-alpha1', room : '2.0.0-beta01',
lifecycle : '2.0.0-beta01', lifecycle : '2.0.0-beta01',
rxKotlin : '2.2.0', rxKotlin : '2.2.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