Unverified Commit c0b2083b authored by Ergashev Adizbek's avatar Ergashev Adizbek Committed by GitHub

Merge branch 'develop' into swipe-to-reply

parents 38c960d8 fdf25924
......@@ -2,7 +2,7 @@
"formatVersion": 1,
"database": {
"version": 11,
"identityHash": "fb9f1c815809b0217d326452aeb34e92",
"identityHash": "f0e15bc95a0bb09b052c484704dd3abd",
"entities": [
{
"tableName": "users",
......@@ -59,7 +59,7 @@
},
{
"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, `topic` TEXT, `announcement` TEXT, `description` TEXT, `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, `muted` TEXT, 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 )",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` TEXT NOT NULL, `parentId` TEXT, `type` TEXT NOT NULL, `name` TEXT NOT NULL, `fullname` TEXT, `userId` TEXT, `ownerId` TEXT, `readonly` INTEGER, `isDefault` INTEGER, `favorite` INTEGER, `topic` TEXT, `announcement` TEXT, `description` TEXT, `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, `muted` TEXT, 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",
......@@ -73,6 +73,12 @@
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "parentId",
"columnName": "parentId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "type",
"columnName": "type",
......@@ -1099,7 +1105,7 @@
],
"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, \"fb9f1c815809b0217d326452aeb34e92\")"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"f0e15bc95a0bb09b052c484704dd3abd\")"
]
}
}
\ No newline at end of file
This diff is collapsed.
......@@ -15,6 +15,7 @@ import chat.rocket.android.server.domain.favicon
import chat.rocket.android.server.domain.isLdapAuthenticationEnabled
import chat.rocket.android.server.domain.isPasswordResetEnabled
import chat.rocket.android.server.domain.model.Account
import chat.rocket.android.server.domain.siteName
import chat.rocket.android.server.domain.wideTile
import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI
......@@ -50,6 +51,7 @@ class LoginPresenter @Inject constructor(
) {
// TODO - we should validate the current server when opening the app, and have a nonnull get()
private var currentServer = serverInteractor.get()!!
private val token = tokenRepository.get(currentServer)
private lateinit var client: RocketChatClient
private lateinit var settings: PublicSettings
......@@ -140,8 +142,15 @@ class LoginPresenter @Inject constructor(
val logo = settings.wideTile()?.let {
currentServer.serverLogoUrl(it)
}
val thumb = currentServer.avatarUrl(username)
val account = Account(currentServer, icon, logo, username, thumb)
val thumb = currentServer.avatarUrl(username, token?.userId, token?.authToken)
val account = Account(
settings.siteName() ?: currentServer,
currentServer,
icon,
logo,
username,
thumb
)
saveAccountInteractor.save(account)
}
......
......@@ -14,6 +14,7 @@ import chat.rocket.android.server.domain.SaveCurrentServerInteractor
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.favicon
import chat.rocket.android.server.domain.model.Account
import chat.rocket.android.server.domain.siteName
import chat.rocket.android.server.domain.wideTile
import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI
......@@ -54,6 +55,7 @@ class LoginOptionsPresenter @Inject constructor(
) {
// TODO - we should validate the current server when opening the app, and have a nonnull get()
private var currentServer = serverInteractor.get()!!
private val token = tokenRepository.get(currentServer)
private lateinit var client: RocketChatClient
private lateinit var settings: PublicSettings
private lateinit var credentialToken: String
......@@ -180,8 +182,15 @@ class LoginOptionsPresenter @Inject constructor(
val logo = settings.wideTile()?.let {
currentServer.serverLogoUrl(it)
}
val thumb = currentServer.avatarUrl(username)
val account = Account(currentServer, icon, logo, username, thumb)
val thumb = currentServer.avatarUrl(username, token?.userId, token?.authToken)
val account = Account(
settings.siteName() ?: currentServer,
currentServer,
icon,
logo,
username,
thumb
)
saveAccountInteractor.save(account)
}
......
......@@ -12,6 +12,7 @@ import chat.rocket.android.server.domain.SaveCurrentServerInteractor
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.favicon
import chat.rocket.android.server.domain.model.Account
import chat.rocket.android.server.domain.siteName
import chat.rocket.android.server.domain.wideTile
import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI
......@@ -39,7 +40,8 @@ class RegisterUsernamePresenter @Inject constructor(
) {
private val currentServer = serverInteractor.get()!!
private val client: RocketChatClient = factory.get(currentServer)
private var settings: PublicSettings = settingsInteractor.get(serverInteractor.get()!!)
private var settings: PublicSettings = settingsInteractor.get(currentServer)
private val token = tokenRepository.get(currentServer)
fun registerUsername(username: String, userId: String, authToken: String) {
launchUI(strategy) {
......@@ -72,15 +74,22 @@ class RegisterUsernamePresenter @Inject constructor(
}
}
private suspend fun saveAccount(username: String) {
private fun saveAccount(username: String) {
val icon = settings.favicon()?.let {
currentServer.serverLogoUrl(it)
}
val logo = settings.wideTile()?.let {
currentServer.serverLogoUrl(it)
}
val thumb = currentServer.avatarUrl(username)
val account = Account(currentServer, icon, logo, username, thumb)
val thumb = currentServer.avatarUrl(username, token?.userId, token?.authToken)
val account = Account(
settings.siteName() ?: currentServer,
currentServer,
icon,
logo,
username,
thumb
)
saveAccountInteractor.save(account)
}
}
\ No newline at end of file
......@@ -10,8 +10,10 @@ import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.SaveAccountInteractor
import chat.rocket.android.server.domain.SaveCurrentServerInteractor
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.favicon
import chat.rocket.android.server.domain.model.Account
import chat.rocket.android.server.domain.siteName
import chat.rocket.android.server.domain.wideTile
import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI
......@@ -38,10 +40,12 @@ class SignupPresenter @Inject constructor(
private val analyticsManager: AnalyticsManager,
private val factory: RocketChatClientFactory,
private val saveAccountInteractor: SaveAccountInteractor,
tokenRepository: TokenRepository,
settingsInteractor: GetSettingsInteractor
) {
private val currentServer = serverInteractor.get()!!
private var settings: PublicSettings = settingsInteractor.get(serverInteractor.get()!!)
private var settings: PublicSettings = settingsInteractor.get(currentServer)
private val token = tokenRepository.get(currentServer)
fun signup(name: String, username: String, password: String, email: String) {
val client = factory.get(currentServer)
......@@ -98,8 +102,15 @@ class SignupPresenter @Inject constructor(
val logo = settings.wideTile()?.let {
currentServer.serverLogoUrl(it)
}
val thumb = currentServer.avatarUrl(me.username!!)
val account = Account(currentServer, icon, logo, me.username!!, thumb)
val thumb = currentServer.avatarUrl(me.username!!, token?.userId, token?.authToken)
val account = Account(
settings.siteName() ?: currentServer,
currentServer,
icon,
logo,
me.username!!,
thumb
)
saveAccountInteractor.save(account)
}
}
\ No newline at end of file
......@@ -13,6 +13,7 @@ import chat.rocket.android.server.domain.SaveCurrentServerInteractor
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.favicon
import chat.rocket.android.server.domain.model.Account
import chat.rocket.android.server.domain.siteName
import chat.rocket.android.server.domain.wideTile
import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI
......@@ -43,7 +44,8 @@ class TwoFAPresenter @Inject constructor(
val settingsInteractor: GetSettingsInteractor
) {
private val currentServer = serverInteractor.get()!!
private var settings: PublicSettings = settingsInteractor.get(serverInteractor.get()!!)
private var settings: PublicSettings = settingsInteractor.get(currentServer)
private val token = tokenRepository.get(currentServer)
fun authenticate(
usernameOrEmail: String,
......@@ -101,8 +103,15 @@ class TwoFAPresenter @Inject constructor(
val logo = settings.wideTile()?.let {
currentServer.serverLogoUrl(it)
}
val thumb = currentServer.avatarUrl(me.username!!)
val account = Account(currentServer, icon, logo, me.username!!, thumb)
val thumb = currentServer.avatarUrl(me.username!!, token?.userId, token?.authToken)
val account = Account(
settings.siteName() ?: currentServer,
currentServer,
icon,
logo,
me.username!!,
thumb
)
saveAccountInteractor.save(account)
}
}
\ No newline at end of file
......@@ -56,6 +56,7 @@ class ChatRoomFragmentModule {
context: Application,
repository: SettingsRepository,
userInteractor: GetCurrentUserInteractor,
tokenRepository: TokenRepository,
@Named("currentServer") serverUrl: String,
permissionsInteractor: PermissionsInteractor
): RoomUiModelMapper {
......@@ -63,6 +64,7 @@ class ChatRoomFragmentModule {
context,
repository.get(serverUrl),
userInteractor,
tokenRepository,
serverUrl,
permissionsInteractor
)
......
......@@ -29,6 +29,7 @@ import chat.rocket.android.server.domain.JobSchedulerInteractor
import chat.rocket.android.server.domain.MessagesRepository
import chat.rocket.android.server.domain.PermissionsInteractor
import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.UsersRepository
import chat.rocket.android.server.domain.uploadMaxFileSize
import chat.rocket.android.server.domain.uploadMimeTypeFilter
......@@ -101,6 +102,7 @@ class ChatRoomPresenter @Inject constructor(
private val jobSchedulerInteractor: JobSchedulerInteractor,
private val messageHelper: MessageHelper,
private val dbManager: DatabaseManager,
tokenRepository: TokenRepository,
getSettingsInteractor: GetSettingsInteractor,
serverInteractor: GetCurrentServerInteractor,
factory: ConnectionManagerFactory
......@@ -109,6 +111,7 @@ class ChatRoomPresenter @Inject constructor(
private val manager = factory.create(currentServer)
private val client = manager.client
private var settings: PublicSettings = getSettingsInteractor.get(serverInteractor.get()!!)
private val token = tokenRepository.get(currentServer)
private val currentLoggedUsername = userHelper.username()
private val messagesChannel = Channel<Message>()
......@@ -327,7 +330,7 @@ class ChatRoomPresenter @Inject constructor(
timestamp = Instant.now().toEpochMilli(),
sender = SimpleUser(user?.id, user?.username ?: username, user?.name),
attachments = null,
avatar = currentServer.avatarUrl(username ?: ""),
avatar = currentServer.avatarUrl(username!!, token?.userId, token?.authToken),
channels = null,
editedAt = null,
editedBy = null,
......@@ -812,7 +815,7 @@ class ChatRoomPresenter @Inject constructor(
val sender = it.sender
val username = sender?.username ?: ""
val name = sender?.name ?: ""
val avatarUrl = currentServer.avatarUrl(username)
val avatarUrl = currentServer.avatarUrl(username, token?.userId, token?.authToken)
val found = members.firstOrNull { member -> member.username == username }
val status = if (found != null) found.status else UserStatus.Offline()
val searchList = mutableListOf(username, name)
......@@ -833,7 +836,7 @@ class ChatRoomPresenter @Inject constructor(
activeUsers.addAll(others.map {
val username = it.username ?: ""
val name = it.name ?: ""
val avatarUrl = currentServer.avatarUrl(username)
val avatarUrl = currentServer.avatarUrl(username, token?.userId, token?.authToken)
val searchList = mutableListOf(username, name)
PeopleSuggestionUiModel(
avatarUrl,
......@@ -869,7 +872,7 @@ class ChatRoomPresenter @Inject constructor(
val searchList = mutableListOf(username, name)
it.emails?.forEach { email -> searchList.add(email.address) }
PeopleSuggestionUiModel(
currentServer.avatarUrl(username),
currentServer.avatarUrl(username, token?.userId, token?.authToken),
username, username, name, it.status, false, searchList
)
}.filterNot { filterSelfOut && self != null && self == it.text })
......@@ -931,6 +934,7 @@ class ChatRoomPresenter @Inject constructor(
ChatRoom(
id = id,
subscriptionId = subscriptionId,
parentId = parentId,
type = roomTypeOf(type),
unread = unread,
broadcast = broadcast ?: false,
......@@ -974,6 +978,7 @@ class ChatRoomPresenter @Inject constructor(
ChatRoom(
id = id,
subscriptionId = subscriptionId,
parentId = parentId,
type = roomTypeOf(type),
unread = unread,
broadcast = broadcast ?: false,
......
......@@ -108,7 +108,7 @@ class UiModelMapper @Inject constructor(
readReceipts.forEach {
list.add(
ReadReceiptViewModel(
avatar = baseUrl.avatarUrl(it.user.username ?: ""),
avatar = baseUrl.avatarUrl(it.user.username!!, token?.userId, token?.authToken),
name = userHelper.displayName(it.user),
time = DateTimeHelper.getTime(DateTimeHelper.getLocalDateTime(it.timestamp))
)
......@@ -173,6 +173,7 @@ class UiModelMapper @Inject constructor(
ChatRoom(
id = id,
subscriptionId = subscriptionId,
parentId = parentId,
type = roomTypeOf(type),
unread = unread,
broadcast = broadcast ?: false,
......@@ -525,7 +526,7 @@ class UiModelMapper @Inject constructor(
val username = message.sender?.username ?: "?"
return baseUrl.let {
baseUrl.avatarUrl(username)
baseUrl.avatarUrl(username, token?.userId, token?.authToken)
}
}
......
......@@ -8,11 +8,13 @@ import chat.rocket.android.db.model.ChatRoom
import chat.rocket.android.server.domain.GetCurrentUserInteractor
import chat.rocket.android.server.domain.PermissionsInteractor
import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.showLastMessage
import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.server.domain.useSpecialCharsOnRoom
import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.date
import chat.rocket.android.util.extensions.isNotNullNorEmpty
import chat.rocket.android.util.extensions.localDateTime
import chat.rocket.common.model.RoomType
import chat.rocket.common.model.User
......@@ -26,10 +28,12 @@ class RoomUiModelMapper(
private val context: Application,
private val settings: PublicSettings,
private val userInteractor: GetCurrentUserInteractor,
private val tokenRepository: TokenRepository,
private val serverUrl: String,
private val permissions: PermissionsInteractor
) {
private val currentUser by lazy { userInteractor.get() }
private val token by lazy { tokenRepository.get(serverUrl) }
fun map(
rooms: List<ChatRoom>,
......@@ -80,7 +84,7 @@ class RoomUiModelMapper(
private fun mapUser(user: User): RoomUiModel = with(user) {
val name = mapName(user.username!!, user.name)
val status = user.status
val avatar = serverUrl.avatarUrl(user.username!!)
val avatar = serverUrl.avatarUrl(user.username!!, token?.userId, token?.authToken)
val username = user.username!!
RoomUiModel(
......@@ -98,7 +102,7 @@ class RoomUiModelMapper(
id = id,
name = name!!,
type = type,
avatar = serverUrl.avatarUrl(name!!, isGroupOrChannel = true),
avatar = serverUrl.avatarUrl(name!!, token?.userId, token?.authToken, isGroupOrChannel = true),
lastMessage = if (showLastMessage) {
mapLastMessage(
lastMessage?.sender?.id, lastMessage?.sender?.username,
......@@ -113,36 +117,40 @@ class RoomUiModelMapper(
)
}
fun map(chatRoom: ChatRoom, showLastMessage: Boolean = true): RoomUiModel = with(chatRoom.chatRoom) {
val isUnread = alert || unread > 0
val type = roomTypeOf(type)
val status = chatRoom.status?.let { userStatusOf(it) }
val roomName = mapName(name, fullname)
val favorite = favorite
val timestamp = mapDate(lastMessageTimestamp ?: updatedAt)
val avatar = if (type is RoomType.DirectMessage) {
serverUrl.avatarUrl(name)
} else {
serverUrl.avatarUrl(name, isGroupOrChannel = true)
}
val unread = mapUnread(unread)
val lastMessage = if (showLastMessage) {
mapLastMessage(
fun map(chatRoom: ChatRoom, showLastMessage: Boolean = true): RoomUiModel =
with(chatRoom.chatRoom) {
val isUnread = alert || unread > 0
val type = roomTypeOf(type)
val status = chatRoom.status?.let { userStatusOf(it) }
val roomName = mapName(name, fullname)
val favorite = favorite
val timestamp = mapDate(lastMessageTimestamp ?: updatedAt)
val avatar =
if (type is RoomType.DirectMessage) {
serverUrl.avatarUrl(name, token?.userId, token?.authToken)
} else {
serverUrl.avatarUrl(name, token?.userId, token?.authToken, isGroupOrChannel = true)
}
val unread = mapUnread(unread)
val lastMessage = if (showLastMessage) {
mapLastMessage(
lastMessageUserId,
chatRoom.lastMessageUserName,
chatRoom.lastMessageUserFullName,
lastMessageText,
type is RoomType.DirectMessage
)
} else {
null
}
val hasMentions = mapMentions(userMentions, groupMentions)
val open = open
val lastMessageMarkdown = lastMessage?.let { Markwon.markdown(context, it.toString()).toString() }
)
} else {
null
}
val hasMentions = mapMentions(userMentions, groupMentions)
val open = open
val lastMessageMarkdown =
lastMessage?.let { Markwon.markdown(context, it.toString()).toString() }
RoomUiModel(
RoomUiModel(
id = id,
isDiscussion = parentId.isNotNullNorEmpty(),
name = roomName,
type = type,
avatar = avatar,
......@@ -157,8 +165,8 @@ class RoomUiModelMapper(
username = if (type is RoomType.DirectMessage) name else null,
muted = muted.orEmpty(),
writable = isChannelWritable(muted)
)
}
)
}
private fun isChannelWritable(muted: List<String>?): Boolean {
val canWriteToReadOnlyChannels = permissions.canPostToReadOnlyChannels()
......
......@@ -11,6 +11,9 @@ import chat.rocket.android.chatrooms.adapter.model.RoomUiModel
import chat.rocket.android.util.extension.setTextViewAppearance
import chat.rocket.common.model.RoomType
import chat.rocket.common.model.UserStatus
import com.bumptech.glide.Glide
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.bumptech.glide.request.RequestOptions
import kotlinx.android.synthetic.main.item_chat.view.*
import kotlinx.android.synthetic.main.unread_messages_badge.view.*
......@@ -19,6 +22,7 @@ class RoomViewHolder(itemView: View, private val listener: (RoomUiModel) -> Unit
private val resources: Resources = itemView.resources
private val channelIcon: Drawable = resources.getDrawable(R.drawable.ic_hashtag_12dp, null)
private val groupIcon: Drawable = resources.getDrawable(R.drawable.ic_lock_12_dp, null)
private val discussionIcon: Drawable = resources.getDrawable(R.drawable.ic_discussion_20dp, null)
private val onlineIcon: Drawable = resources.getDrawable(R.drawable.ic_status_online_12dp, null)
private val awayIcon: Drawable = resources.getDrawable(R.drawable.ic_status_away_12dp, null)
private val busyIcon: Drawable = resources.getDrawable(R.drawable.ic_status_busy_12dp, null)
......@@ -27,10 +31,18 @@ class RoomViewHolder(itemView: View, private val listener: (RoomUiModel) -> Unit
override fun bindViews(data: RoomItemHolder) {
val room = data.data
with(itemView) {
image_avatar.setImageURI(room.avatar)
val avatar = room.avatar
Glide.with(image_avatar.context)
.load(room.avatar)
.apply(RequestOptions.bitmapTransform(RoundedCorners(10)))
.into(image_avatar)
text_chat_name.text = room.name
if (room.status != null && room.type is RoomType.DirectMessage) {
if (room.isDiscussion) {
image_chat_icon.setImageDrawable(discussionIcon)
} else if (room.status != null && room.type is RoomType.DirectMessage) {
image_chat_icon.setImageDrawable(getStatusDrawable(room.status))
} else {
image_chat_icon.setImageDrawable(getRoomDrawable(room.type))
......
......@@ -5,6 +5,7 @@ import chat.rocket.common.model.UserStatus
data class RoomUiModel(
val id: String,
val isDiscussion: Boolean = false,
val type: RoomType,
val name: CharSequence,
val avatar: String,
......
......@@ -86,12 +86,20 @@ class ChatRoomsFragmentModule {
@PerFragment
fun provideRoomMapper(
context: Application,
repository: SettingsRepository,
settingsRepository: SettingsRepository,
userInteractor: GetCurrentUserInteractor,
tokenRepository: TokenRepository,
@Named("currentServer") serverUrl: String,
permissionsInteractor: PermissionsInteractor
): RoomUiModelMapper {
return RoomUiModelMapper(context, repository.get(serverUrl), userInteractor, serverUrl, permissionsInteractor)
return RoomUiModelMapper(
context,
settingsRepository.get(serverUrl),
userInteractor,
tokenRepository,
serverUrl,
permissionsInteractor
)
}
@Provides
......
......@@ -11,6 +11,7 @@ import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.main.presentation.MainNavigator
import chat.rocket.android.server.domain.SettingsRepository
import chat.rocket.android.server.domain.SortingAndGroupingInteractor
import chat.rocket.android.server.domain.siteName
import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.server.domain.useSpecialCharsOnRoom
import chat.rocket.android.server.infrastructure.ConnectionManager
......@@ -52,7 +53,7 @@ class ChatRoomsPresenter @Inject constructor(
fun toDirectory() = navigator.toDirectory()
fun getCurrentServerName() = view.setupToolbar(currentServer)
fun getCurrentServerName() = view.setupToolbar(settings.siteName() ?: currentServer)
fun getSortingAndGroupingPreferences() {
with(sortingAndGroupingInteractor) {
......@@ -93,6 +94,7 @@ class ChatRoomsPresenter @Inject constructor(
val entity = ChatRoomEntity(
id = id,
subscriptionId = "",
parentId = null,
type = type.toString(),
name = username ?: name.toString(),
fullname = name.toString(),
......
......@@ -475,6 +475,7 @@ class DatabaseManager(val context: Application, val serverUrl: String) {
return ChatRoomEntity(
id = room.id,
subscriptionId = subscription.id,
parentId = subscription.parentId,
type = room.type.toString(),
name = room.name ?: subscription.name
?: throw NullPointerException(), // this should be filtered on the SDK
......@@ -516,6 +517,7 @@ class DatabaseManager(val context: Application, val serverUrl: String) {
return ChatRoomEntity(
id = id,
subscriptionId = subscriptionId,
parentId = parentId,
type = type.toString(),
name = name,
fullname = fullName,
......
......@@ -25,7 +25,7 @@ import chat.rocket.android.emoji.internal.db.StringListConverter
AttachmentFieldEntity::class, AttachmentActionEntity::class, UrlEntity::class,
ReactionEntity::class, MessagesSync::class
],
version = 11,
version = 12,
exportSchema = true
)
@TypeConverters(StringListConverter::class)
......
......@@ -26,6 +26,7 @@ import chat.rocket.android.emoji.internal.db.StringListConverter
data class ChatRoomEntity(
@PrimaryKey var id: String,
var subscriptionId: String,
var parentId: String?,
var type: String,
var name: String,
var fullname: String? = null,
......
......@@ -146,6 +146,7 @@ class DirectoryPresenter @Inject constructor(
val chatRoomEntity = ChatRoomEntity(
id = directMessage.id,
parentId = null,
name = username,
description = null,
type = RoomType.DIRECT_MESSAGE,
......
package chat.rocket.android.directory.uimodel
import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.common.model.Token
import chat.rocket.core.model.DirectoryResult
class DirectoryUiModel(
private val directoryResult: DirectoryResult,
private val baseUrl: String?
private val baseUrl: String?,
private val token: Token?
) {
val id: String = directoryResult.id
val channelAvatarUri: String?
......@@ -22,12 +24,12 @@ class DirectoryUiModel(
}
private fun getChannelAvatar(): String? {
return baseUrl?.avatarUrl(name, isGroupOrChannel = true)
return baseUrl?.avatarUrl(name, token?.userId, token?.authToken, isGroupOrChannel = true)
}
private fun getUserAvatar(): String? {
return directoryResult.username?.let {
baseUrl?.avatarUrl(it)
baseUrl?.avatarUrl(it, token?.userId, token?.authToken)
}
}
}
package chat.rocket.android.directory.uimodel
import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.baseUrl
import chat.rocket.core.model.DirectoryResult
import chat.rocket.core.model.Value
......@@ -9,13 +10,14 @@ import javax.inject.Named
class DirectoryUiModelMapper @Inject constructor(
getSettingsInteractor: GetSettingsInteractor,
@Named("currentServer") private val currentServer: String
@Named("currentServer") private val currentServer: String,
tokenRepository: TokenRepository
) {
private var settings: Map<String, Value<Any>> = getSettingsInteractor.get(currentServer)
private val baseUrl = settings.baseUrl()
private val token = tokenRepository.get(currentServer)
fun mapToUiModelList(directoryList: List<DirectoryResult>): List<DirectoryUiModel> {
return directoryList.map { DirectoryUiModel(it, baseUrl) }
return directoryList.map { DirectoryUiModel(it, baseUrl, token) }
}
}
\ No newline at end of file
......@@ -26,7 +26,7 @@ object AndroidPermissionsHelper {
}
fun hasCameraPermission(context: Context): Boolean {
return AndroidPermissionsHelper.checkPermission(context, Manifest.permission.CAMERA)
return checkPermission(context, Manifest.permission.CAMERA)
}
fun getCameraPermission(fragment: Fragment) {
......@@ -50,10 +50,10 @@ object AndroidPermissionsHelper {
fun checkWritingPermission(context: Context) {
if (context is ContextThemeWrapper) {
val activity = if (context.baseContext is Activity) context.baseContext as Activity else context as Activity
AndroidPermissionsHelper.requestPermission(
requestPermission(
activity,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
AndroidPermissionsHelper.WRITE_EXTERNAL_STORAGE_CODE
WRITE_EXTERNAL_STORAGE_CODE
)
}
}
......
......@@ -2,6 +2,7 @@ package chat.rocket.android.members.uimodel
import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.common.model.Token
import chat.rocket.common.model.User
import chat.rocket.common.model.UserStatus
import chat.rocket.core.model.Value
......@@ -9,7 +10,8 @@ import chat.rocket.core.model.Value
class MemberUiModel(
private val member: User,
private val settings: Map<String, Value<Any>>,
private val baseUrl: String?
private val baseUrl: String?,
private val token: Token?
) {
val userId: String = member.id
val avatarUri: String?
......@@ -33,7 +35,7 @@ class MemberUiModel(
private fun getUserAvatar(): String? {
val username = member.username ?: "?"
return baseUrl?.let {
baseUrl.avatarUrl(username, format = "png")
baseUrl.avatarUrl(username, token?.userId, token?.authToken, format = "png")
}
}
......
......@@ -2,19 +2,24 @@ package chat.rocket.android.members.uimodel
import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.baseUrl
import chat.rocket.common.model.User
import chat.rocket.core.model.Value
import javax.inject.Inject
import javax.inject.Named
class MemberUiModelMapper @Inject constructor(
serverInteractor: GetCurrentServerInteractor,
getSettingsInteractor: GetSettingsInteractor
getSettingsInteractor: GetSettingsInteractor,
@Named("currentServer") private val currentServer: String,
tokenRepository: TokenRepository
) {
private var settings: Map<String, Value<Any>> = getSettingsInteractor.get(serverInteractor.get()!!)
private val baseUrl = settings.baseUrl()
private val token = tokenRepository.get(currentServer)
fun mapToUiModelList(memberList: List<User>): List<MemberUiModel> {
return memberList.map { MemberUiModel(it, settings, baseUrl) }
return memberList.map { MemberUiModel(it, settings, baseUrl, token) }
}
}
......@@ -57,6 +57,7 @@ class ProfilePresenter @Inject constructor(
private val serverUrl = serverInteractor.get()!!
private val client: RocketChatClient = factory.get(serverUrl)
private val user = userHelper.user()
private val token = tokenRepository.get(serverUrl)
fun loadUserProfile() {
launchUI(strategy) {
......@@ -68,7 +69,7 @@ class ProfilePresenter @Inject constructor(
view.showProfile(
me.status.toString(),
serverUrl.avatarUrl(me.username ?: ""),
serverUrl.avatarUrl(me.username!!, token?.userId, token?.authToken),
me.name ?: "",
me.username ?: "",
me.emails?.getOrNull(0)?.address ?: ""
......@@ -97,7 +98,7 @@ class ProfilePresenter @Inject constructor(
view.showProfileUpdateSuccessfullyMessage()
view.showProfile(
user.status.toString(),
serverUrl.avatarUrl(user.username ?: ""),
serverUrl.avatarUrl(user.username!!, token?.userId, token?.authToken),
name,
username,
email
......@@ -127,7 +128,15 @@ class ProfilePresenter @Inject constructor(
uriInteractor.getInputStream(uri)
}
}
user?.username?.let { view.reloadUserAvatar(serverUrl.avatarUrl(it)) }
user?.username?.let {
view.reloadUserAvatar(
serverUrl.avatarUrl(
it,
token?.userId,
token?.authToken
)
)
}
} catch (exception: RocketChatException) {
exception.message?.let {
view.showMessage(it)
......@@ -155,7 +164,15 @@ class ProfilePresenter @Inject constructor(
}
}
user?.username?.let { view.reloadUserAvatar(serverUrl.avatarUrl(it)) }
user?.username?.let {
view.reloadUserAvatar(
serverUrl.avatarUrl(
it,
token?.userId,
token?.authToken
)
)
}
} catch (exception: RocketChatException) {
exception.message?.let {
view.showMessage(it)
......@@ -175,7 +192,15 @@ class ProfilePresenter @Inject constructor(
user?.id?.let { id ->
retryIO { client.resetAvatar(id) }
}
user?.username?.let { view.reloadUserAvatar(serverUrl.avatarUrl(it)) }
user?.username?.let {
view.reloadUserAvatar(
serverUrl.avatarUrl(
it,
token?.userId,
token?.authToken
)
)
}
} catch (exception: RocketChatException) {
exception.message?.let {
view.showMessage(it)
......
......@@ -3,6 +3,7 @@ package chat.rocket.android.profile.ui
import DrawableHelper
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.os.Build
import android.os.Bundle
......@@ -21,6 +22,9 @@ import androidx.fragment.app.Fragment
import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.helper.AndroidPermissionsHelper
import chat.rocket.android.helper.AndroidPermissionsHelper.getCameraPermission
import chat.rocket.android.helper.AndroidPermissionsHelper.hasCameraPermission
import chat.rocket.android.main.ui.MainActivity
import chat.rocket.android.profile.presentation.ProfilePresenter
import chat.rocket.android.profile.presentation.ProfileView
......@@ -35,12 +39,15 @@ import chat.rocket.android.util.invalidateFirebaseToken
import chat.rocket.common.model.UserStatus
import chat.rocket.common.model.userStatusOf
import com.facebook.drawee.backends.pipeline.Fresco
import com.google.android.material.snackbar.Snackbar
import dagger.android.support.AndroidSupportInjection
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.Observables
import kotlinx.android.synthetic.main.app_bar.*
import kotlinx.android.synthetic.main.avatar_profile.*
import kotlinx.android.synthetic.main.fragment_profile.*
import kotlinx.android.synthetic.main.fragment_profile.view_dim
import kotlinx.android.synthetic.main.fragment_profile.view_loading
import kotlinx.android.synthetic.main.update_avatar_options.*
import javax.inject.Inject
......@@ -52,8 +59,10 @@ private const val REQUEST_CODE_FOR_PERFORM_CAMERA = 2
fun newInstance() = ProfileFragment()
class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
@Inject lateinit var presenter: ProfilePresenter
@Inject lateinit var analyticsManager: AnalyticsManager
@Inject
lateinit var presenter: ProfilePresenter
@Inject
lateinit var analyticsManager: AnalyticsManager
private var currentStatus = ""
private var currentName = ""
private var currentUsername = ""
......@@ -223,7 +232,13 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
}
button_take_a_photo.setOnClickListener {
dispatchTakePicture(REQUEST_CODE_FOR_PERFORM_CAMERA)
context?.let {
if (hasCameraPermission(it)) {
dispatchTakePicture(REQUEST_CODE_FOR_PERFORM_CAMERA)
} else {
getCameraPermission(this)
}
}
hideUpdateAvatarOptions()
}
......@@ -331,4 +346,28 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
}.show()
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
AndroidPermissionsHelper.CAMERA_CODE -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted
dispatchTakePicture(REQUEST_CODE_FOR_PERFORM_CAMERA)
} else {
// permission denied
Snackbar.make(
relative_layout,
R.string.msg_camera_permission_denied,
Snackbar.LENGTH_SHORT
).show()
}
return
}
}
}
}
......@@ -4,6 +4,7 @@ import se.ansman.kotshi.JsonSerializable
@JsonSerializable
data class Account(
val serverName: String?,
val serverUrl: String,
val serverLogo: String?,
val serverBg: String?,
......
......@@ -13,7 +13,7 @@ class ServerViewHolder(itemView: View, private val currentServerUrl: String) :
fun bind(account: Account) {
with(itemView) {
Glide.with(context).load(account.serverLogo).into(image_server)
text_server_name.text = account.serverUrl
text_server_name.text = account.serverName ?: account.serverUrl
text_server_url.text = account.serverUrl
image_check.isInvisible = currentServerUrl != account.serverUrl
}
......
......@@ -56,6 +56,7 @@ class SettingsPresenter @Inject constructor(
tokenView = view,
navigator = navigator
) {
private val token = tokenRepository.get(currentServer)
fun setupView() {
launchUI(strategy) {
......@@ -70,7 +71,7 @@ class SettingsPresenter @Inject constructor(
userHelper.user()?.let { user ->
view.setupSettingsView(
currentServer.avatarUrl(me.username ?: ""),
currentServer.avatarUrl(me.username!!, token?.userId, token?.authToken),
userHelper.displayName(user) ?: me.username ?: "",
me.status.toString(),
permissions.isAdministrationEnabled(),
......
......@@ -8,12 +8,14 @@ import chat.rocket.android.db.model.ChatRoomEntity
import chat.rocket.android.db.model.UserEntity
import chat.rocket.android.server.domain.CurrentServerRepository
import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.isJitsiEnabled
import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.retryIO
import chat.rocket.common.model.RoomType
import chat.rocket.common.model.Token
import chat.rocket.common.util.ifNull
import chat.rocket.core.internal.rest.createDirectMessage
import kotlinx.coroutines.Dispatchers
......@@ -26,6 +28,7 @@ class UserDetailsPresenter @Inject constructor(
private val dbManager: DatabaseManager,
private val strategy: CancelStrategy,
private val navigator: ChatRoomNavigator,
tokenRepository: TokenRepository,
settingsInteractor: GetSettingsInteractor,
serverInteractor: CurrentServerRepository,
factory: ConnectionManagerFactory
......@@ -35,6 +38,7 @@ class UserDetailsPresenter @Inject constructor(
private val client = manager.client
private val interactor = FetchChatRoomsInteractor(client, dbManager)
private val settings = settingsInteractor.get(currentServer)
private val token = tokenRepository.get(currentServer)
private lateinit var userEntity: UserEntity
fun loadUserDetails(userId: String) {
......@@ -44,7 +48,13 @@ class UserDetailsPresenter @Inject constructor(
dbManager.getUser(userId)?.let {
userEntity = it
val avatarUrl =
userEntity.username?.let { username -> currentServer.avatarUrl(avatar = username) }
userEntity.username?.let { username ->
currentServer.avatarUrl(
username,
token?.userId,
token?.authToken
)
}
val username = userEntity.username
val name = userEntity.name
val utcOffset =
......@@ -89,6 +99,7 @@ class UserDetailsPresenter @Inject constructor(
val chatRoomEntity = ChatRoomEntity(
id = directMessage.id,
name = userEntity.username ?: userEntity.name.orEmpty(),
parentId = null,
description = null,
type = RoomType.DIRECT_MESSAGE,
fullname = userEntity.name,
......
......@@ -21,13 +21,15 @@ fun String.sanitize(): String {
fun String.avatarUrl(
avatar: String,
userId: String?,
token: String?,
isGroupOrChannel: Boolean = false,
format: String = "jpeg"
): String {
return if (isGroupOrChannel) {
"${removeTrailingSlash()}/avatar/%23${avatar.removeTrailingSlash()}?format=$format"
"${removeTrailingSlash()}/avatar/%23${avatar.removeTrailingSlash()}?format=$format&rc_uid=$userId&rc_token=$token"
} else {
"${removeTrailingSlash()}/avatar/${avatar.removeTrailingSlash()}?format=$format"
"${removeTrailingSlash()}/avatar/${avatar.removeTrailingSlash()}?format=$format&rc_uid=$userId&rc_token=$token"
}
}
......
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:fillColor="#9EA2A8"
android:fillType="nonZero"
android:pathData="M17.0178,9.0088C17.4002,8.2308 17.479,7.9789 17.479,7.6459C17.479,4.8323 15.0667,2.5397 12.1027,2.5397C9.1391,2.5397 6.7273,4.832 6.7273,7.6459C6.7273,10.6045 9.2399,12.7514 12.8986,12.7514L13.0419,12.7522L13.2199,12.7522C15.7971,12.7522 17.3253,12.49 17.9955,12.099C17.4393,11.8181 17.312,11.7402 17.0644,11.4817C16.7269,11.1295 16.5447,10.6642 16.5903,10.1635C16.6148,9.8935 16.6686,9.7447 16.7751,9.5219C16.8362,9.3843 16.8928,9.2651 17.0178,9.0088ZM18.3011,10.1607C18.1916,10.3871 18.2091,10.4113 18.8615,10.7397C19.8228,11.2213 20.24,11.6696 19.8612,12.4352C19.1566,13.8599 16.8659,14.3395 13.2199,14.3395L13.0419,14.3395L12.8892,14.3387C8.3595,14.3387 5.0607,11.5237 5.0607,7.6459C5.0607,3.9545 8.2195,0.9524 12.1027,0.9524C15.9862,0.9524 19.1457,3.9547 19.1457,7.6459C19.1457,8.2881 18.979,8.7628 18.5273,9.6817C18.4105,9.9212 18.3589,10.0296 18.3011,10.1607ZM13.5847,16.3438C13.4018,16.575 13.2033,16.7931 12.9903,16.9977C12.7079,16.9977 12.4278,16.9894 12.1501,16.973L12.251,15.4273C12.2578,15.4187 12.2646,15.4102 12.2714,15.4016L13.5847,16.3438ZM12.2535,15.3888L12.2714,15.4016C12.2744,15.3979 12.2774,15.3941 12.2804,15.3903C12.5148,15.4037 12.7523,15.4104 12.9928,15.4104L13.1738,15.4114L13.3848,15.4114C13.6721,15.4114 13.9523,15.4089 14.2253,15.4036C13.9139,15.9928 13.5075,16.528 13.0195,16.9979L12.9928,16.9977C12.9919,16.9977 12.9911,16.9977 12.9903,16.9977C11.5566,18.3752 9.469,19.1391 7.111,19.1391L6.9581,19.1399L6.7801,19.1399C4.1004,19.1399 2.2612,18.8789 1.204,18.2903L0.9763,18.1635C0.5978,17.9163 0.3174,17.6159 0.1388,17.2549C-0.1741,16.6227 0.056,16.2068 0.6871,15.8098L1.263,15.5183C1.6568,15.319 1.6328,15.3349 1.7194,15.2446C1.7599,15.2023 1.7736,15.1649 1.7694,15.1185C1.7642,15.0606 1.772,15.0866 1.7081,14.9517C1.6576,14.8377 1.6095,14.736 1.491,14.4933C1.0219,13.5389 0.8746,13.0988 0.8746,12.4656C0.8746,11.0845 1.3214,9.7648 2.1303,8.6606C2.129,8.6512 2.1278,8.6417 2.1265,8.6322C2.5652,8.0375 3.1029,7.5134 3.7168,7.0817C3.713,7.1803 3.7112,7.2792 3.7112,7.3786C3.7112,7.962 3.7726,8.5253 3.8907,9.0644C3.8873,9.068 3.8839,9.0717 3.8805,9.0753L3.896,9.0884L3.8618,9.0953C3.0102,10.0132 2.521,11.2015 2.521,12.4656C2.521,12.7985 2.5998,13.0505 2.9842,13.8326C3.1146,14.0999 3.1702,14.2175 3.2126,14.3161C3.3274,14.5534 3.3842,14.703 3.4097,14.9832C3.4553,15.4839 3.2731,15.9492 2.9356,16.3014C2.6884,16.5596 2.561,16.6376 2.0044,16.9188C2.6743,17.3097 4.2025,17.5719 6.7801,17.5719L6.9487,17.5719L7.1108,17.5711C9.3389,17.5711 11.1786,16.7606 12.251,15.4273L12.2535,15.3888ZM1.9145,16.9641C1.6344,17.1044 1.5191,17.1878 1.5466,17.1462C1.6888,16.9311 1.6902,16.6667 1.6467,16.5786C1.7065,16.6996 1.8245,16.8138 2.0044,16.9188C1.9756,16.9333 1.9457,16.9484 1.9145,16.9641ZM2.2655,9.4174C2.2101,9.1681 2.165,8.9157 2.1303,8.6606C2.2904,8.4422 2.4646,8.2321 2.6523,8.0317L3.8805,9.0753C3.8743,9.0819 3.868,9.0886 3.8618,9.0953L2.2655,9.4174ZM2.8863,15.5497L2.0452,16.92L2.8273,18.3216C3.5014,17.9804 3.7692,17.8068 4.1368,17.4308C4.8511,17.5089 5.7278,17.5526 6.7801,17.5526L6.9581,17.5526L7.1013,17.5518C9.3708,17.5518 11.1972,16.724 12.2535,15.3888C12.4966,15.4031 12.7431,15.4104 12.9928,15.4104L13.1738,15.4114L13.3848,15.4114C13.6721,15.4114 13.9523,15.4089 14.2253,15.4036C13.0193,17.6858 10.387,19.1584 7.1108,19.1584L6.9581,19.1592L6.7801,19.1592C3.1341,19.1592 0.8434,18.6796 0.1388,17.2549C-0.24,16.4893 0.1772,16.041 1.1385,15.5594C1.7909,15.231 1.8084,15.2068 1.6989,14.9803C1.6411,14.8493 1.5895,14.7409 1.4727,14.5014C1.021,13.5824 0.8543,13.1078 0.8543,12.4656C0.8543,10.2609 1.9815,8.302 3.7168,7.0817C3.713,7.1803 3.7112,7.2792 3.7112,7.3786C3.7112,7.9706 3.7745,8.542 3.896,9.0884C3.0537,9.9876 2.5412,11.1713 2.5412,12.4656C2.5412,12.7951 2.6193,13.0447 3.0005,13.8203C3.1256,14.0767 3.1822,14.1961 3.2434,14.3338C3.3508,14.5585 3.405,14.7087 3.4299,14.9815C3.4528,15.2336 3.4186,15.4768 3.3365,15.7014C3.1322,15.6538 2.9811,15.6024 2.8863,15.5497Z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
\ No newline at end of file
......@@ -8,21 +8,22 @@
android:paddingStart="@dimen/screen_edge_left_and_right_padding"
android:paddingTop="@dimen/chat_item_top_and_bottom_padding"
android:paddingEnd="@dimen/screen_edge_left_and_right_padding"
android:paddingBottom="@dimen/chat_item_top_and_bottom_padding">
android:paddingBottom="@dimen/chat_item_top_and_bottom_padding"
tools:context=".chatrooms.adapter.RoomsAdapter">
<com.facebook.drawee.view.SimpleDraweeView
<ImageView
android:id="@+id/image_avatar"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginTop="5dp"
android:layout_marginTop="2dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:roundedCornerRadius="4dp" />
tools:src="@tools:sample/avatars" />
<ImageView
android:id="@+id/image_chat_icon"
android:layout_width="12dp"
android:layout_height="0dp"
android:layout_height="12dp"
android:layout_marginStart="16dp"
app:layout_constraintBottom_toBottomOf="@+id/text_chat_name"
app:layout_constraintStart_toEndOf="@+id/image_avatar"
......@@ -35,6 +36,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/text_view_drawable_padding"
android:layout_marginEnd="@dimen/text_view_drawable_padding"
android:textDirection="locale"
app:layout_constraintEnd_toStartOf="@+id/text_timestamp"
app:layout_constraintStart_toEndOf="@+id/image_chat_icon"
......
......@@ -19,7 +19,7 @@
<string name="title_admin_panel">Панель админа</string>
<string name="title_password">Изменить пароль</string>
<string name="title_update_profile">Обновить профиль</string>
<string name="title_choose_language">Choose Language</string> <!-- TODO Add translation -->
<string name="title_choose_language">Изменить язык</string>
<string name="title_create_channel">Создать новый канал</string>
<string name="title_channel_details">О канале</string>
<string name="title_topic">Тема</string>
......@@ -74,23 +74,23 @@
<string name="msg_delete_account">Удалить аккаунт</string>
<string name="msg_change_status">Изменить статус</string>
<string-array name="languages"> <!-- TODO Add translations -->
<item>English</item>
<item>Arabic</item>
<item>German</item>
<item>Spanish</item>
<item>Persian</item>
<item>French</item>
<item>Hindi (IN)</item>
<item>Italian</item>
<item>Japanese</item>
<item>Portuguese (BR)</item>
<item>Portuguese (PT)</item>
<item>Russian (RU)</item>
<item>Turkish</item>
<item>Ukrainian</item>
<item>Chinese (CN)</item>
<item>Chinese (TW)</item>
<string-array name="languages">
<item>Английский</item>
<item>Арабский</item>
<item>Немецкий</item>
<item>Испанский</item>
<item>Персидский</item>
<item>Французский</item>
<item>Хинди (IN)</item>
<item>Итальянский</item>
<item>Японский</item>
<item>Португальский (BR)</item>
<item>Португальский (PT)</item>
<item>Русский (RU)</item>
<item>Турецкий</item>
<item>Украинский</item>
<item>Китайский (CN)</item>
<item>Китайский (TW)</item>
</string-array>
<!-- Regular information messages -->
......@@ -203,7 +203,7 @@
<string name="msg_storage_permission_denied">Необходимо разрешение на использование хранилища</string>
<string name="msg_server">Сервер</string>
<string name="msg_add_new_server">Добавить новый сервер</string>
<string name="msg_directory">Директория</string>
<string name="msg_directory">Каталог</string>
<!-- Create channel messages -->
<string name="msg_private_channel">Приватный</string>
......@@ -344,7 +344,7 @@
<string name="msg_channels">Каналы</string>
<string name="msg_users">Пользователи</string>
<string name="msg_search_for_global_users">Поиск глобальных пользователей</string>
<string name="msg_search_for_global_users_description">При активации станет возможен поиск любого пользователя из других компаний или серверов.</string>
<string name="msg_search_for_global_users_description">При активации станет возможен поиск пользователей на других серверах.</string>
<string name="header_private_groups">Приватные каналы</string>
<string name="header_direct_messages">Личная переписка</string>
<string name="header_live_chats">Живые чаты</string>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment