Unverified Commit 5382b1e5 authored by Filipe de Lima Brito's avatar Filipe de Lima Brito Committed by GitHub

Merge branch 'develop' into fix/display-username

parents d00b8247 65ebc5bc
This diff is collapsed.
......@@ -61,7 +61,14 @@ interface Analytics {
fun logServerSwitch(serverUrl: String, serverCount: Int) {}
/**
* Logs the admin opening.
* Logs the admin opening event.
*/
fun logOpenAdmin() {}
/**
* Logs the reset password event.
*
* @param resetPasswordSucceeded True if successful reset password, false otherwise.
*/
fun logResetPassword(resetPasswordSucceeded: Boolean) {}
}
......@@ -70,4 +70,10 @@ class AnalyticsManager @Inject constructor(
analytics.forEach { it.logOpenAdmin() }
}
}
fun logResetPassword(resetPasswordSucceeded: Boolean) {
if (analyticsTrackingInteractor.get()) {
analytics.forEach { it.logResetPassword(resetPasswordSucceeded) }
}
}
}
......@@ -61,6 +61,10 @@ abstract class BaseViewHolder<T : BaseUiModel<*>>(
reactionListener?.onReactionAdded(messageId, emoji)
}
}
override fun onReactionLongClicked(shortname: String, isCustom: Boolean, url: String?, usernames: List<String>) {
reactionListener?.onReactionLongClicked(shortname, isCustom,url, usernames)
}
}
val context = itemView.context
......
......@@ -75,7 +75,7 @@ class MessageReactionsAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>()
class ReactionViewHolder(
view: View,
private val listener: EmojiReactionListener?
) : RecyclerView.ViewHolder(view), View.OnClickListener {
) : RecyclerView.ViewHolder(view), View.OnClickListener, View.OnLongClickListener {
@Inject
lateinit var localRepository: LocalRepository
......@@ -121,6 +121,8 @@ class MessageReactionsAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>()
view_flipper_reaction.setOnClickListener(this@ReactionViewHolder)
text_count.setOnClickListener(this@ReactionViewHolder)
view_flipper_reaction.setOnLongClickListener(this@ReactionViewHolder)
text_count.setOnLongClickListener(this@ReactionViewHolder)
}
}
......@@ -132,6 +134,11 @@ class MessageReactionsAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>()
}
}
}
override fun onLongClick(v: View?): Boolean {
listener?.onReactionLongClicked(reaction.shortname, reaction.isCustom, reaction.url, reaction.usernames)
return true
}
}
class AddReactionViewHolder(
......
......@@ -34,11 +34,11 @@ import chat.rocket.android.server.domain.uploadMimeTypeFilter
import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import chat.rocket.android.server.infraestructure.state
import chat.rocket.android.util.extension.compressImageAndGetByteArray
import chat.rocket.android.util.extension.getByteArray
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.getBitmpap
import chat.rocket.android.util.extensions.exhaustive
import chat.rocket.android.util.retryDB
import chat.rocket.android.util.retryIO
import chat.rocket.common.RocketChatException
import chat.rocket.common.model.RoomType
......@@ -82,7 +82,6 @@ import kotlinx.coroutines.experimental.launch
import kotlinx.coroutines.experimental.withContext
import org.threeten.bp.Instant
import timber.log.Timber
import java.io.InputStream
import java.util.*
import javax.inject.Inject
......@@ -138,9 +137,12 @@ class ChatRoomPresenter @Inject constructor(
} finally {
// User has at least an 'owner' or 'moderator' role.
val userCanMod = isOwnerOrMod()
val chatRoom = dbManager.getRoom(roomId)
val muted = chatRoom?.chatRoom?.muted ?: emptyList()
// Can post anyway if has the 'post-readonly' permission on server.
val userCanPost = userCanMod || permissions.canPostToReadOnlyChannels()
chatIsBroadcast = dbManager.getRoom(roomId)?.chatRoom?.run {
val userCanPost = userCanMod || permissions.canPostToReadOnlyChannels() ||
!muted.contains(currentLoggedUsername)
chatIsBroadcast = chatRoom?.chatRoom?.run {
broadcast
} ?: false
view.onRoomUpdated(userCanPost, chatIsBroadcast, userCanMod)
......@@ -901,77 +903,81 @@ class ChatRoomPresenter @Inject constructor(
// TODO: move this to new interactor or FetchChatRoomsInteractor?
private suspend fun getChatRoomAsync(roomId: String): ChatRoom? = withContext(CommonPool) {
return@withContext dbManager.chatRoomDao().get(roomId)?.let {
with(it.chatRoom) {
ChatRoom(
id = id,
subscriptionId = subscriptionId,
type = roomTypeOf(type),
unread = unread,
broadcast = broadcast ?: false,
alert = alert,
fullName = fullname,
name = name,
favorite = favorite ?: false,
default = isDefault ?: false,
readonly = readonly,
open = open,
lastMessage = null,
archived = false,
status = null,
user = null,
userMentions = userMentions,
client = client,
announcement = null,
description = null,
groupMentions = groupMentions,
roles = null,
topic = null,
lastSeen = this.lastSeen,
timestamp = timestamp,
updatedAt = updatedAt
)
retryDB("getRoom($roomId)") {
dbManager.chatRoomDao().get(roomId)?.let {
with(it.chatRoom) {
ChatRoom(
id = id,
subscriptionId = subscriptionId,
type = roomTypeOf(type),
unread = unread,
broadcast = broadcast ?: false,
alert = alert,
fullName = fullname,
name = name,
favorite = favorite ?: false,
default = isDefault ?: false,
readonly = readonly,
open = open,
lastMessage = null,
archived = false,
status = null,
user = null,
userMentions = userMentions,
client = client,
announcement = null,
description = null,
groupMentions = groupMentions,
roles = null,
topic = null,
lastSeen = this.lastSeen,
timestamp = timestamp,
updatedAt = updatedAt
)
}
}
}
}
// TODO: move this to new interactor or FetchChatRoomsInteractor?
private suspend fun getChatRoomsAsync(name: String? = null): List<ChatRoom> = withContext(CommonPool) {
return@withContext dbManager.chatRoomDao().getAllSync().filter {
if (name == null) {
return@filter true
}
it.chatRoom.name == name || it.chatRoom.fullname == name
}.map {
with(it.chatRoom) {
ChatRoom(
id = id,
subscriptionId = subscriptionId,
type = roomTypeOf(type),
unread = unread,
broadcast = broadcast ?: false,
alert = alert,
fullName = fullname,
name = name ?: "",
favorite = favorite ?: false,
default = isDefault ?: false,
readonly = readonly,
open = open,
lastMessage = null,
archived = false,
status = null,
user = null,
userMentions = userMentions,
client = client,
announcement = null,
description = null,
groupMentions = groupMentions,
roles = null,
topic = null,
lastSeen = this.lastSeen,
timestamp = timestamp,
updatedAt = updatedAt
)
retryDB("getAllSync()") {
dbManager.chatRoomDao().getAllSync().filter {
if (name == null) {
return@filter true
}
it.chatRoom.name == name || it.chatRoom.fullname == name
}.map {
with(it.chatRoom) {
ChatRoom(
id = id,
subscriptionId = subscriptionId,
type = roomTypeOf(type),
unread = unread,
broadcast = broadcast ?: false,
alert = alert,
fullName = fullname,
name = name ?: "",
favorite = favorite ?: false,
default = isDefault ?: false,
readonly = readonly,
open = open,
lastMessage = null,
archived = false,
status = null,
user = null,
userMentions = userMentions,
client = client,
announcement = null,
description = null,
groupMentions = groupMentions,
roles = null,
topic = null,
lastSeen = this.lastSeen,
timestamp = timestamp,
updatedAt = updatedAt
)
}
}
}
}
......
......@@ -60,6 +60,7 @@ import chat.rocket.android.emoji.EmojiKeyboardPopup
import chat.rocket.android.emoji.EmojiParser
import chat.rocket.android.emoji.EmojiPickerPopup
import chat.rocket.android.emoji.EmojiReactionListener
import chat.rocket.android.emoji.internal.GlideApp
import chat.rocket.android.emoji.internal.isCustom
import chat.rocket.android.helper.EndlessRecyclerViewScrollListener
import chat.rocket.android.helper.ImageHelper
......@@ -84,6 +85,8 @@ import dagger.android.support.AndroidSupportInjection
import io.reactivex.Observable
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import kotlinx.android.synthetic.main.emoji_image_row_item.*
import kotlinx.android.synthetic.main.emoji_row_item.*
import kotlinx.android.synthetic.main.fragment_chat_room.*
import kotlinx.android.synthetic.main.message_attachment_options.*
import kotlinx.android.synthetic.main.message_composer.*
......@@ -91,6 +94,7 @@ import kotlinx.android.synthetic.main.message_list.*
import timber.log.Timber
import java.io.File
import java.io.IOException
import kotlinx.android.synthetic.main.reaction_praises_list_item.*
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger
import javax.inject.Inject
......@@ -611,7 +615,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
}
override fun showGenericErrorMessage(){
override fun showGenericErrorMessage() {
ui {
showMessage(getString(R.string.msg_generic_error))
}
......@@ -688,6 +692,44 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
presenter.react(messageId, emoji.shortname)
}
override fun onReactionLongClicked(shortname: String, isCustom: Boolean, url: String?, usernames: List<String>) {
val layout = LayoutInflater.from(requireContext()).inflate(R.layout.reaction_praises_list_item, null)
val dialog = AlertDialog.Builder(requireContext())
.setView(layout)
.setCancelable(true)
with(layout) {
view_flipper.displayedChild = if (isCustom) 1 else 0
if (isCustom && url != null) {
val glideRequest = if (url.endsWith("gif", true)) {
GlideApp.with(requireContext()).asGif()
} else {
GlideApp.with(requireContext()).asBitmap()
}
glideRequest.load(url).into(emoji_image_view)
} else {
emoji_view.text = EmojiParser.parse(requireContext(), shortname)
}
var listing = ""
if (usernames.size == 1) {
listing = usernames.first()
} else {
usernames.forEachIndexed { index, username ->
listing += if (index == usernames.size - 1) "|$username" else "$username, "
}
listing = listing.replace(", |", " ${requireContext().getString(R.string.msg_and)} ")
}
text_view_usernames.text = requireContext().resources.getQuantityString(
R.plurals.msg_reacted_with_, usernames.size, listing, shortname)
dialog.show()
}
}
override fun showReactionsPopup(messageId: String) {
ui {
val emojiPickerPopup = EmojiPickerPopup(it)
......@@ -787,9 +829,17 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
private fun setupMessageComposer(canPost: Boolean) {
if (isReadOnly && !canPost) {
if (!canPost) {
text_room_is_read_only.isVisible = true
input_container.isVisible = false
text_room_is_read_only.setText(
if (isReadOnly) {
R.string.msg_this_room_is_read_only
} else {
// Not a read-only channel but user has been muted.
R.string.msg_muted_on_this_channel
}
)
} else if (!isSubscribed && roomTypeOf(chatRoomType) !is RoomType.DirectMessage) {
input_container.isVisible = false
button_join_chat.isVisible = true
......
......@@ -6,5 +6,6 @@ data class ReactionUiModel(
val unicode: CharSequence,
val count: Int,
val usernames: List<String> = emptyList(),
var url: String? = null
)
\ No newline at end of file
var url: String? = null,
val isCustom: Boolean = false
)
......@@ -19,6 +19,7 @@ import chat.rocket.android.dagger.scope.PerFragment
import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.emoji.EmojiParser
import chat.rocket.android.emoji.EmojiRepository
import chat.rocket.android.emoji.internal.isCustom
import chat.rocket.android.helper.MessageHelper
import chat.rocket.android.helper.MessageParser
import chat.rocket.android.helper.UserHelper
......@@ -31,6 +32,7 @@ import chat.rocket.android.server.domain.messageReadReceiptEnabled
import chat.rocket.android.server.domain.messageReadReceiptStoreUsers
import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import chat.rocket.android.util.extension.orFalse
import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.ifNotNullNorEmpty
import chat.rocket.android.util.extensions.isNotNullNorEmpty
......@@ -469,7 +471,7 @@ class UiModelMapper @Inject constructor(
val list = mutableListOf<ReactionUiModel>()
val customEmojis = EmojiRepository.getCustomEmojis()
it.getShortNames().forEach { shortname ->
val usernames = it.getUsernames(shortname) ?: emptyList()
val usernames = it.getUsernames(shortname).orEmpty()
val count = usernames.size
val custom = customEmojis.firstOrNull { emoji -> emoji.shortname == shortname }
list.add(
......@@ -478,7 +480,8 @@ class UiModelMapper @Inject constructor(
unicode = EmojiParser.parse(context, shortname),
count = count,
usernames = usernames,
url = custom?.url)
url = custom?.url,
isCustom = custom != null)
)
}
list
......
......@@ -14,5 +14,6 @@ data class RoomUiModel(
val alert: Boolean = false,
val lastMessage: CharSequence? = null,
val status: UserStatus? = null,
val username: String? = null
)
\ No newline at end of file
val username: String? = null,
val muted: List<String> = emptyList()
)
......@@ -3,9 +3,12 @@ package chat.rocket.android.chatrooms.infrastructure
import androidx.lifecycle.LiveData
import chat.rocket.android.db.ChatRoomDao
import chat.rocket.android.db.model.ChatRoom
import chat.rocket.android.util.retryDB
import javax.inject.Inject
class ChatRoomsRepository @Inject constructor(private val dao: ChatRoomDao){
class ChatRoomsRepository @Inject constructor(private val dao: ChatRoomDao) {
// TODO - check how to use retryDB here - suspend
fun getChatRooms(order: Order): LiveData<List<ChatRoom>> {
return when(order) {
Order.ACTIVITY -> dao.getAll()
......@@ -15,9 +18,10 @@ class ChatRoomsRepository @Inject constructor(private val dao: ChatRoomDao){
}
}
fun search(query: String) = dao.searchSync(query)
suspend fun search(query: String) =
retryDB("roomSearch($query)") { dao.searchSync(query) }
fun count() = dao.count()
suspend fun count() = retryDB("roomsCount") { dao.count() }
enum class Order {
ACTIVITY,
......
......@@ -13,6 +13,7 @@ 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.util.extension.launchUI
import chat.rocket.android.util.retryDB
import chat.rocket.android.util.retryIO
import chat.rocket.common.RocketChatException
import chat.rocket.common.model.RoomType
......@@ -41,11 +42,31 @@ class ChatRoomsPresenter @Inject constructor(
private val client = manager.client
private val settings = settingsRepository.get(currentServer)
fun loadChatRoom(roomId: String) {
launchUI(strategy) {
view.showLoadingRoom("")
try {
val room = dbManager.getRoom(roomId)
if (room != null) {
loadChatRoom(room.chatRoom, true)
} else {
Timber.d("Error loading channel")
view.showGenericErrorMessage()
}
} catch (ex: Exception) {
Timber.d(ex, "Error loading channel")
view.showGenericErrorMessage()
} finally {
view.hideLoadingRoom()
}
}
}
fun loadChatRoom(chatRoom: RoomUiModel) {
launchUI(strategy) {
view.showLoadingRoom(chatRoom.name)
try {
val room = dbManager.getRoom(chatRoom.id)
val room = retryDB("getRoom(${chatRoom.id}") { dbManager.getRoom(chatRoom.id) }
if (room != null) {
loadChatRoom(room.chatRoom, true)
} else {
......@@ -56,7 +77,8 @@ class ChatRoomsPresenter @Inject constructor(
type = type.toString(),
name = username ?: name.toString(),
fullname = name.toString(),
open = open
open = open,
muted = muted
)
loadChatRoom(entity, false)
}
......
......@@ -84,8 +84,7 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
if (bundle != null) {
chatRoomId = bundle.getString(BUNDLE_CHAT_ROOM_ID)
chatRoomId?.let {
// TODO - bring back support to load a room from id.
//presenter.goToChatRoomWithId(it)
presenter.loadChatRoom(it)
chatRoomId = null
}
}
......
......@@ -27,7 +27,7 @@ import kotlinx.coroutines.experimental.launch
import kotlinx.coroutines.experimental.newSingleThreadContext
import kotlinx.coroutines.experimental.withContext
import timber.log.Timber
import java.security.InvalidParameterException
import java.lang.IllegalArgumentException
import kotlin.coroutines.experimental.coroutineContext
......@@ -171,6 +171,6 @@ fun Query.asSortingOrder(): ChatRoomsRepository.Order {
ChatRoomsRepository.Order.ACTIVITY
}
}
else -> throw InvalidParameterException("Should be ByName or ByActivity")
else -> throw IllegalArgumentException("Should be ByName or ByActivity")
}
}
......@@ -2,6 +2,7 @@ package chat.rocket.android.db
import androidx.room.Database
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import chat.rocket.android.db.model.AttachmentActionEntity
import chat.rocket.android.db.model.AttachmentEntity
import chat.rocket.android.db.model.AttachmentFieldEntity
......@@ -14,6 +15,7 @@ import chat.rocket.android.db.model.MessagesSync
import chat.rocket.android.db.model.ReactionEntity
import chat.rocket.android.db.model.UrlEntity
import chat.rocket.android.db.model.UserEntity
import chat.rocket.android.emoji.internal.db.StringListConverter
@Database(
entities = [
......@@ -23,11 +25,12 @@ import chat.rocket.android.db.model.UserEntity
AttachmentFieldEntity::class, AttachmentActionEntity::class, UrlEntity::class,
ReactionEntity::class, MessagesSync::class
],
version = 10,
version = 12,
exportSchema = true
)
@TypeConverters(StringListConverter::class)
abstract class RCDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
abstract fun chatRoomDao(): ChatRoomDao
abstract fun messageDao(): MessageDao
}
\ No newline at end of file
}
......@@ -5,6 +5,8 @@ import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.Index
import androidx.room.PrimaryKey
import androidx.room.TypeConverters
import chat.rocket.android.emoji.internal.db.StringListConverter
@Entity(tableName = "chatrooms",
indices = [
......@@ -20,6 +22,7 @@ import androidx.room.PrimaryKey
ForeignKey(entity = UserEntity::class, parentColumns = ["id"], childColumns = ["lastMessageUserId"])
]
)
@TypeConverters(StringListConverter::class)
data class ChatRoomEntity(
@PrimaryKey var id: String,
var subscriptionId: String,
......@@ -42,7 +45,8 @@ data class ChatRoomEntity(
var lastMessageText: String? = null,
var lastMessageUserId: String? = null,
var lastMessageTimestamp: Long? = null,
var broadcast: Boolean? = false
var broadcast: Boolean? = false,
var muted: List<String>? = null
)
data class ChatRoom(
......@@ -52,4 +56,4 @@ data class ChatRoom(
var status: String?,
var lastMessageUserName: String?,
var lastMessageUserFullName: String?
)
\ No newline at end of file
)
......@@ -5,6 +5,7 @@ import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.retryDB
import chat.rocket.common.RocketChatException
import chat.rocket.common.model.roomTypeOf
import chat.rocket.common.util.ifNull
......@@ -36,7 +37,7 @@ class FavoriteMessagesPresenter @Inject constructor(
view.showLoading()
dbManager.getRoom(roomId)?.let {
val favoriteMessages =
client.getFavoriteMessages(roomId, roomTypeOf(it.chatRoom.type), offset)
client.getFavoriteMessages(roomId, roomTypeOf(it.chatRoom.type), offset)
val messageList = mapper.map(favoriteMessages.result, asNotReversed = true)
view.showFavoriteMessages(messageList)
offset += 1 * 30
......
......@@ -7,6 +7,7 @@ import chat.rocket.android.files.uimodel.FileUiModel
import chat.rocket.android.files.uimodel.FileUiModelMapper
import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.retryDB
import chat.rocket.common.RocketChatException
import chat.rocket.common.model.roomTypeOf
import chat.rocket.common.util.ifNull
......
......@@ -6,6 +6,7 @@ import chat.rocket.android.members.uimodel.MemberUiModel
import chat.rocket.android.members.uimodel.MemberUiModelMapper
import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.retryDB
import chat.rocket.common.RocketChatException
import chat.rocket.common.model.roomTypeOf
import chat.rocket.common.util.ifNull
......@@ -38,7 +39,7 @@ class MembersPresenter @Inject constructor(
view.showLoading()
dbManager.getRoom(roomId)?.let {
val members =
client.getMembers(roomId, roomTypeOf(it.chatRoom.type), offset, 60)
client.getMembers(roomId, roomTypeOf(it.chatRoom.type), offset, 60)
val memberUiModels = mapper.mapToUiModelList(members.result)
view.showMembers(memberUiModels, members.total)
offset += 1 * 60L
......
......@@ -5,6 +5,7 @@ import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.retryDB
import chat.rocket.common.RocketChatException
import chat.rocket.common.model.roomTypeOf
import chat.rocket.common.util.ifNull
......@@ -36,7 +37,7 @@ class PinnedMessagesPresenter @Inject constructor(
view.showLoading()
dbManager.getRoom(roomId)?.let {
val pinnedMessages =
client.getPinnedMessages(roomId, roomTypeOf(it.chatRoom.type), offset)
client.getPinnedMessages(roomId, roomTypeOf(it.chatRoom.type), offset)
val messageList = mapper.map(pinnedMessages.result, asNotReversed = true)
view.showPinnedMessages(messageList)
offset += 1 * 30
......
......@@ -296,11 +296,8 @@ class PushManager @Inject constructor(
}
private fun getContentIntent(context: Context, notificationId: Int, pushMessage: PushMessage, grouped: Boolean = false): PendingIntent {
val notificationIntent = context.changeServerIntent(pushMessage.info.host, chatRoomId = pushMessage.info.roomId)
// TODO - add support to go directly to the chatroom
/*if (!isGrouped) {
notificationIntent.putExtra(EXTRA_ROOM_ID, pushMessage.info.roomId)
}*/
val roomId = if (!grouped) pushMessage.info.roomId else null
val notificationIntent = context.changeServerIntent(pushMessage.info.host, chatRoomId = roomId)
return PendingIntent.getActivity(context, random.nextInt(), notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT)
}
......
......@@ -7,6 +7,7 @@ import chat.rocket.android.db.model.FullMessage
import chat.rocket.android.db.model.ReactionEntity
import chat.rocket.android.db.model.UrlEntity
import chat.rocket.android.db.model.UserEntity
import chat.rocket.android.util.retryDB
import chat.rocket.common.model.SimpleRoom
import chat.rocket.common.model.SimpleUser
import chat.rocket.core.model.Message
......@@ -135,14 +136,18 @@ class DatabaseMessageMapper(private val dbManager: DatabaseManager) {
with(attachment) {
val fields = if (hasFields) {
withContext(CommonPool) {
dbManager.messageDao().getAttachmentFields(attachment._id)
retryDB("getAttachmentFields(${attachment._id})") {
dbManager.messageDao().getAttachmentFields(attachment._id)
}
}.map { Field(it.title, it.value) }
} else {
null
}
val actions = if (hasActions) {
withContext(CommonPool) {
dbManager.messageDao().getAttachmentActions(attachment._id)
retryDB("getAttachmentActions(${attachment._id})") {
dbManager.messageDao().getAttachmentActions(attachment._id)
}
}.mapNotNull { mapAction(it) }
} else {
null
......@@ -183,29 +188,6 @@ class DatabaseMessageMapper(private val dbManager: DatabaseManager) {
return list
}
/*private suspend fun mapColorAttachmentWithFields(entity: AttachmentEntity): ColorAttachment {
val fields = withContext(CommonPool) {
dbManager.messageDao().getAttachmentFields(entity._id)
}.map { Field(it.title, it.value) }
return with(entity) {
ColorAttachment(
color = Color.Custom(color ?: DEFAULT_COLOR_STR),
text = text ?: "",
fallback = fallback,
fields = fields)
}
}
private suspend fun mapActionAttachment(attachment: AttachmentEntity): ActionsAttachment {
val actions = withContext(CommonPool) {
dbManager.messageDao().getAttachmentActions(attachment._id)
}.mapNotNull { mapAction(it) }
return with(attachment) {
// TODO - remove the default "vertical" value from here...
ActionsAttachment(title, actions, buttonAlignment ?: "vertical")
}
}*/
private fun mapAction(action: AttachmentActionEntity): Action? {
return when (action.type) {
"button" -> ButtonAction(action.type, action.text, action.url, action.isWebView,
......@@ -214,13 +196,4 @@ class DatabaseMessageMapper(private val dbManager: DatabaseManager) {
else -> null
}
}
/*private suspend fun mapAuthorAttachment(attachment: AttachmentEntity): AuthorAttachment {
val fields = withContext(CommonPool) {
dbManager.messageDao().getAttachmentFields(attachment._id)
}.map { Field(it.title, it.value) }
return with(attachment) {
AuthorAttachment(authorLink!!, authorIcon, authorName, fields)
}
}*/
}
\ No newline at end of file
......@@ -4,6 +4,7 @@ import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.db.Operation
import chat.rocket.android.db.model.MessagesSync
import chat.rocket.android.server.domain.MessagesRepository
import chat.rocket.android.util.retryDB
import chat.rocket.core.model.Message
import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.withContext
......@@ -14,25 +15,31 @@ class DatabaseMessagesRepository(
) : MessagesRepository {
override suspend fun getById(id: String): Message? = withContext(CommonPool) {
dbManager.messageDao().getMessageById(id)?.let { message -> mapper.map(message) }
retryDB("getMessageById($id)") {
dbManager.messageDao().getMessageById(id)?.let { message -> mapper.map(message) }
}
}
override suspend fun getByRoomId(roomId: String): List<Message> = withContext(CommonPool) {
// FIXME - investigate how to avoid this distinctBy here, since DAO is returning a lot of
// duplicate rows (something related to our JOINS and relations on Room)
dbManager.messageDao().getMessagesByRoomId(roomId)
.distinctBy { it.message.message.id }
.let { messages ->
mapper.map(messages)
}
retryDB("getMessagesByRoomId($roomId)") {
dbManager.messageDao().getMessagesByRoomId(roomId)
.distinctBy { it.message.message.id }
.let { messages ->
mapper.map(messages)
}
}
}
override suspend fun getRecentMessages(roomId: String, count: Long): List<Message> = withContext(CommonPool) {
dbManager.messageDao().getRecentMessagesByRoomId(roomId, count)
.distinctBy { it.message.message.id }
.let { messages ->
mapper.map(messages)
}
retryDB("getRecentMessagesByRoomId($roomId, $count)") {
dbManager.messageDao().getRecentMessagesByRoomId(roomId, count)
.distinctBy { it.message.message.id }
.let { messages ->
mapper.map(messages)
}
}
}
override suspend fun save(message: Message) {
......@@ -45,20 +52,24 @@ class DatabaseMessagesRepository(
override suspend fun removeById(id: String) {
withContext(CommonPool) {
dbManager.messageDao().delete(id)
retryDB("delete($id)") { dbManager.messageDao().delete(id) }
}
}
override suspend fun removeByRoomId(roomId: String) {
withContext(CommonPool) {
dbManager.messageDao().deleteByRoomId(roomId)
retryDB("deleteByRoomId($roomId)") {
dbManager.messageDao().deleteByRoomId(roomId)
}
}
}
override suspend fun getAllUnsent(): List<Message> = withContext(CommonPool) {
dbManager.messageDao().getUnsentMessages()
.distinctBy { it.message.message.id }
.let { mapper.map(it) }
retryDB("getUnsentMessages") {
dbManager.messageDao().getUnsentMessages()
.distinctBy { it.message.message.id }
.let { mapper.map(it) }
}
}
override suspend fun saveLastSyncDate(roomId: String, timeMillis: Long) {
......@@ -66,6 +77,8 @@ class DatabaseMessagesRepository(
}
override suspend fun getLastSyncDate(roomId: String): Long? = withContext(CommonPool) {
dbManager.messageDao().getLastSync(roomId)?.let { it.timestamp }
retryDB("getLastSync($roomId)") {
dbManager.messageDao().getLastSync(roomId)?.let { it.timestamp }
}
}
}
\ No newline at end of file
package chat.rocket.android.settings.password.presentation
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.infraestructure.RocketChatClientFactory
......@@ -14,6 +15,7 @@ import javax.inject.Inject
class PasswordPresenter @Inject constructor(
private val view: PasswordView,
private val strategy: CancelStrategy,
private val analyticsManager: AnalyticsManager,
serverInteractor: GetCurrentServerInteractor,
factory: RocketChatClientFactory
) {
......@@ -30,10 +32,12 @@ class PasswordPresenter @Inject constructor(
client.updateProfile(me.id, null, null, password, null)
}
analyticsManager.logResetPassword(true)
view.showPasswordSuccessfullyUpdatedMessage()
view.hideLoading()
} catch (exception: RocketChatException) {
analyticsManager.logResetPassword(false)
view.showPasswordFailsUpdateMessage(exception.message)
} finally {
view.hideLoading()
}
}
......
package chat.rocket.android.settings.ui
import android.content.ActivityNotFoundException
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.net.toUri
import androidx.fragment.app.Fragment
import chat.rocket.android.R
import chat.rocket.android.about.ui.AboutFragment
......@@ -84,7 +87,15 @@ class SettingsFragment : Fragment(), SettingsView, AdapterView.OnItemClickListen
shareIntent.putExtra(Intent.EXTRA_TEXT, shareSub)
startActivity(Intent.createChooser(shareIntent, getString(R.string.msg_share_using)))
}
resources.getString(R.string.title_rate_us) -> startAppPlayStore()
}
}
private fun startAppPlayStore() {
try {
startActivity(Intent(Intent.ACTION_VIEW, getString(R.string.market_link).toUri()))
} catch (error: ActivityNotFoundException) {
startActivity(Intent(Intent.ACTION_VIEW, getString(R.string.play_store_link).toUri()))
}
}
......
package chat.rocket.android.util
import android.database.sqlite.SQLiteDatabaseLockedException
import chat.rocket.common.RocketChatNetworkErrorException
import kotlinx.coroutines.experimental.TimeoutCancellationException
import kotlinx.coroutines.experimental.delay
......@@ -8,6 +9,7 @@ import timber.log.Timber
import kotlin.coroutines.experimental.coroutineContext
const val DEFAULT_RETRY = 3
private const val DEFAULT_DB_RETRY = 5
suspend fun <T> retryIO(
description: String = "<missing description>",
......@@ -32,6 +34,33 @@ suspend fun <T> retryIO(
currentDelay = (currentDelay * factor).toLong().coerceAtMost(maxDelay)
}
if (!coroutineContext.isActive) throw TimeoutCancellationException("job canceled")
return block() // last attempt
}
suspend fun <T> retryDB(
description: String = "<missing description>",
times: Int = DEFAULT_DB_RETRY,
initialDelay: Long = 100, // 0.1 second
maxDelay: Long = 500, // 0.5 second
factor: Double = 1.2,
block: suspend () -> T): T
{
var currentDelay = initialDelay
repeat(times - 1) { currentTry ->
if (!coroutineContext.isActive) throw TimeoutCancellationException("job canceled")
try {
return block()
} catch (e: SQLiteDatabaseLockedException) {
Timber.d(e, "failed call($currentTry): $description")
e.printStackTrace()
}
if (!coroutineContext.isActive) throw TimeoutCancellationException("job canceled")
delay(currentDelay)
currentDelay = (currentDelay * factor).toLong().coerceAtMost(maxDelay)
}
if (!coroutineContext.isActive) throw TimeoutCancellationException("job canceled")
return block() // last attempt
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center">
<ImageView
android:id="@+id/emoji_image_view"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_gravity="center"
tools:src="@tools:sample/avatars" />
</FrameLayout>
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/emoji_view"
android:layout_width="48dp"
android:layout_height="48dp"
android:foreground="?selectableItemBackground"
android:layout_gravity="center"
android:gravity="center"
android:textColor="#000000"
android:textSize="24sp"
tools:text="😀" />
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorWhite"
android:padding="16dp">
<ViewFlipper
android:id="@+id/view_flipper"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:foregroundGravity="center"
app:layout_constraintTop_toTopOf="parent">
<include layout="@layout/emoji_row_item" />
<include layout="@layout/emoji_image_row_item" />
</ViewFlipper>
<TextView
android:id="@+id/text_view_usernames"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-light"
android:textColor="@color/darkGray"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="@+id/view_flipper"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/view_flipper"
app:layout_constraintTop_toTopOf="@+id/view_flipper"
tools:text="Ann reacted with :grin:" />
</androidx.constraintlayout.widget.ConstraintLayout>
......@@ -16,6 +16,7 @@
<string name="title_settings">Einstellungen</string>
<string name="title_preferences">Preferences</string> <!-- TODO Add translation -->
<string name="title_change_password">Ändere Passwort</string>
<string name="title_rate_us">Bewerten Sie uns</string>
<string name="title_admin_panel">Admin panel</string> <!-- TODO Add translation -->
<string name="title_password">Ändere Passwort</string>
<string name="title_update_profile">Update Profil</string>
......@@ -58,8 +59,9 @@
<string-array name="settings_actions">
<item name="item_preferences">Preferences</item> <!-- TODO Add translation -->
<item name="item_password">Ändere Passwort</item>
<item name="item_password">Über</item>
<item name="item_share_app">App teilen</item>
<item name="item_rate_us">Bewerten Sie uns</item>
<item name="item_password">Über</item>
</string-array>
<!-- Regular information messages -->
......@@ -148,6 +150,13 @@
<string name="msg_continue_with_wordpress">Continue with <b>WordPress</b></string> <!-- TODO Add translation -->
<string name="msg_two_factor_authentication">Two-factor Authentication</string> <!-- TODO Add translation -->
<string name="msg__your_2fa_code">What’s your 2FA code?</string> <!-- TODO Add translation -->
<!-- TODO - Add proper translation -->
<string name="msg_muted_on_this_channel">You are muted on this channel</string>
<!-- TODO - Add proper translation -->
<plurals name="msg_reacted_with_">
<item quantity="one">%1$s reacted with %2$s</item>
<item quantity="other">%1$s reacted with %2$s</item>
</plurals>
<!-- Create channel messages -->
<string name="msg_private_channel">Privat</string>
......
......@@ -15,6 +15,7 @@
<string name="title_settings">Configuraciones</string>
<string name="title_preferences">Preferences</string> <!-- TODO Add translation -->
<string name="title_change_password">Cambia la contraseña</string>
<string name="title_rate_us">Nos califica</string>
<string name="title_admin_panel">Admin panel</string> <!-- TODO Add translation -->
<string name="title_password">Cambia la contraseña</string>
<string name="title_update_profile">Actualización del perfil</string>
......@@ -57,8 +58,9 @@
<string-array name="settings_actions">
<item name="item_preferences">Preferences</item> <!-- TODO Add translation -->
<item name="item_password">Cambia la contraseña</item>
<item name="item_password">Acerca de</item>
<item name="item_share_app">Compartir aplicación</item>
<item name="item_rate_us">Nos califica</item>
<item name="item_password">Acerca de</item>
</string-array>
<!-- Regular information messages -->
......@@ -166,6 +168,13 @@
<string name="msg_view_less">view less</string>
<!-- TODO - Add proper translation -->
<string name="msg_permalink_copied">Permalink copied</string>
<!-- TODO - Add proper translation -->
<string name="msg_muted_on_this_channel">You are muted on this channel</string>
<!-- TODO - Add proper translation -->
<plurals name="msg_reacted_with_">
<item quantity="one">%1$s reacted with %2$s</item>
<item quantity="other">%1$s reacted with %2$s</item>
</plurals>
<!-- Preferences messages -->
<string name="msg_analytics_tracking">Analytics tracking</string> <!-- TODO Add translation -->
......
......@@ -16,6 +16,7 @@
<string name="title_settings">Paramètres</string>
<string name="title_preferences">Préférences</string>
<string name="title_change_password">Changer le mot de passe</string>
<string name="title_rate_us">évaluez nous</string>
<string name="title_admin_panel">Administration</string>
<string name="title_password">Changer le mot de passe</string>
<string name="title_update_profile">Mettre à jour le profil</string>
......@@ -58,8 +59,9 @@
<string-array name="settings_actions">
<item name="item_preferences">Préférences</item>
<item name="item_password">Changer le mot de passe</item>
<item name="item_password">À propos</item>
<item name="item_share_app">Partager l\'application</item>
<item name="item_rate_us">évaluez nous</item>
<item name="item_password">À propos</item>
</string-array>
<!-- Regular information messages -->
......@@ -158,6 +160,13 @@
<string name="msg_view_less">view less</string>
<!-- TODO - Add proper translation -->
<string name="msg_permalink_copied">Permalink copied</string>
<!-- TODO - Add proper translation -->
<string name="msg_muted_on_this_channel">You are muted on this channel</string>
<!-- TODO - Add proper translation -->
<plurals name="msg_reacted_with_">
<item quantity="one">%1$s reacted with %2$s</item>
<item quantity="other">%1$s reacted with %2$s</item>
</plurals>
<!-- Create channel messages -->
<string name="msg_private_channel">Privé</string>
......
......@@ -16,6 +16,7 @@
<string name="title_settings">सेटिंग्स</string>
<string name="title_preferences">प्राथमिकताएँ</string>
<string name="title_change_password">पासवर्ड बदलें</string>
<string name="title_rate_us">हमें रेटिंग दें</string>
<string name="title_admin_panel">एडमिन पैनल</string>
<string name="title_password">पासवर्ड बदलें</string>
<string name="title_update_profile">प्रोफ़ाइल अपडेट करें</string>
......@@ -58,8 +59,9 @@
<string-array name="settings_actions">
<item name="item_preferences">प्राथमिकताएँ</item>
<item name="item_password">पासवर्ड बदलें</item>
<item name="item_password">परिचय</item>
<item name="item_share_app">ऐप शेयर करें</item>
<item name="item_rate_us">हमें रेटिंग दें</item>
<item name="item_password">परिचय</item>
</string-array>
<!-- Regular information messages -->
......@@ -170,6 +172,13 @@
<string name="msg_view_less">कम देखें</string>
<!-- TODO - Add proper translation -->
<string name="msg_permalink_copied">Permalink copied</string>
<!-- TODO - Add proper translation -->
<string name="msg_muted_on_this_channel">You are muted on this channel</string>
<!-- TODO - Add proper translation -->
<plurals name="msg_reacted_with_">
<item quantity="one">%1$s reacted with %2$s</item>
<item quantity="other">%1$s reacted with %2$s</item>
</plurals>
<!-- Preferences messages -->
<string name="msg_analytics_tracking">एनालिटिक्स ट्रैकिंग</string>
......
This diff is collapsed.
......@@ -18,11 +18,13 @@
<string name="title_settings">設定</string>
<string name="title_preferences">環境設定</string>
<string name="title_change_password">パスワードの変更</string>
<string name="title_rate_us">私たちを評価してください</string>
<string name="title_admin_panel">管理パネル</string>
<string name="title_password">パスワードの変更</string>
<string name="title_update_profile">プロフィールの更新</string>
<string name="title_about">About</string>
<string name="title_create_channel">新しいチャネルを作成</string>
<string name="title_are_you_sure">本気ですか?</string>
<!-- Actions -->
<string name="action_connect">接続</string>
......@@ -53,14 +55,15 @@
<string name="action_create_server">新規サーバーを作成</string>
<string name="action_register">登録</string>
<string name="action_confirm">確認</string>
<string name="action_delete_account">Delete account</string> <!-- TODO Add translation -->
<string name="action_delete_account">アカウントを削除する</string>
<!-- Settings List -->
<string-array name="settings_actions">
<item name="item_preferences">環境設定</item>
<item name="item_password">パスワードの変更</item>
<item name="item_password">アプリ情報</item>
<item name="item_share_app">アプリを共有する</item>
<item name="item_rate_us">私たちを評価してください</item>
<item name="item_password">アプリ情報</item>
</string-array>
<!-- Regular information messages -->
......@@ -152,10 +155,14 @@
<string name="msg_continue_with_wordpress"><b>WordPress</b>でログイン</string>
<string name="msg_two_factor_authentication">二要素認証</string>
<string name="msg__your_2fa_code">あなたの 2FA コードは何ですか?</string>
<string name="msg_view_more">更に表示</string>
<string name="msg_view_less">隠す</string>
<string name="msg_muted_on_this_channel">あなたはこのチャンネルでミュートされています</string>
<!-- TODO - Add proper translation -->
<plurals name="msg_reacted_with_">
<item quantity="one">%1$s reacted with %2$s</item>
<item quantity="other">%1$s reacted with %2$s</item>
</plurals>
<!-- Create channel messages -->
<string name="msg_private_channel">プライベート</string>
......@@ -209,7 +216,6 @@
<string name="action_msg_share">Share</string>
<string name="action_title_editing">メッセージの編集</string>
<string name="action_msg_add_reaction">リアクションする</string>
<!-- TODO - Add proper translation -->
<string name="action_msg_copy_permalink">パーマリンクのコピー</string>
<!-- Permission messages -->
......
......@@ -16,6 +16,7 @@
<string name="title_settings">Configurações</string>
<string name="title_preferences">Preferencias</string>
<string name="title_change_password">Alterar senha</string>
<string name="title_rate_us">nos avalie</string>
<string name="title_admin_panel">Painel administrativo</string>
<string name="title_password">Alterar senha</string>
<string name="title_update_profile">Editar perfil</string>
......@@ -58,8 +59,9 @@
<string-array name="settings_actions">
<item name="item_preferences">Preferencias</item>
<item name="item_password">Alterar senha</item>
<item name="item_password">Sobre</item>
<item name="item_share_app">Compartilhe o aplicativo</item>
<item name="item_rate_us">nos avalie</item>
<item name="item_password">Sobre</item>
</string-array>
<!-- Regular information messages -->
......@@ -157,6 +159,11 @@
<string name="msg_view_less">visualizar menos</string>
<!-- TODO - Add proper translation -->
<string name="msg_permalink_copied">Permalink copiado</string>
<string name="msg_muted_on_this_channel">Você está silenciado neste canal</string>
<plurals name="msg_reacted_with_">
<item quantity="one">%1$s reagiu com %2$s</item>
<item quantity="other">%1$s reagiram com %2$s</item>
</plurals>
<!-- Create channel messages -->
<string name="msg_private_channel">Privado</string>
......@@ -185,8 +192,8 @@
<string name="message_welcome">Bem-vindo, %s</string>
<string name="message_removed">Mensagem removida</string>
<string name="message_pinned">Pinou uma mensagem:</string>
<string name="message_muted">Usuário %1$s entrou no modo mudo por %2$s</string>
<string name="message_unmuted">Usuário %1$s saiu do modo mudo por %2$s</string>
<string name="message_muted">Usuário %1$s foi silenciado por %2$s</string>
<string name="message_unmuted">Usuário %1$s saiu do modo silenciado por %2$s</string>
<string name="message_role_add">%1$s foi definido %2$s por %3$s</string>
<string name="message_role_removed">%1$s não é mais %2$s por %3$s</string>
// TODO:Add proper translation.
......
......@@ -16,6 +16,7 @@
<string name="title_settings">Настройки</string>
<string name="title_preferences">Персональные</string>
<string name="title_change_password">Изменить пароль</string>
<string name="title_rate_us">оцените нас</string>
<string name="title_admin_panel">Панель админа</string>
<string name="title_password">Изменить пароль</string>
<string name="title_update_profile">Обновить профиль</string>
......@@ -58,8 +59,9 @@
<string-array name="settings_actions">
<item name="item_preferences">Персональные</item>
<item name="item_password">Изменить пароль</item>
<item name="item_password">О программе</item>
<item name="item_rate_us">оцените нас</item>
<item name="item_share_app">добавить приложение</item>
<item name="item_password">О программе</item>
</string-array>
<!-- Regular information messages -->
......@@ -154,6 +156,14 @@
<string name="msg_view_more">больше</string>
<string name="msg_view_less">меньше</string>
<string name="msg_permalink_copied">Ссылка скопирована</string>
<!-- TODO - Add proper translation -->
<string name="msg_muted_on_this_channel">You are muted on this channel</string>
<!-- TODO - Add proper translation -->
<plurals name="msg_reacted_with_">
<item quantity="one">%1$s reacted with %2$s</item>
<item quantity="few">%1$s reacted with %2$s</item>
<item quantity="many">%1$s reacted with %2$s</item>
</plurals>
<!-- Create channel messages -->
<string name="msg_private_channel">Приватный</string>
......
......@@ -16,6 +16,7 @@
<string name="title_settings">Ayarlar</string>
<string name="title_preferences">Tercihler</string>
<string name="title_change_password">Şifre Değişikliği</string>
<string name="title_rate_us">Bizi değerlendirin</string>
<string name="title_admin_panel">Yönetici Paneli</string>
<string name="title_password">Şifrenizi Değiştirin</string>
<string name="title_update_profile">Profilinizi Düzenleyin</string>
......@@ -58,8 +59,9 @@
<string-array name="settings_actions">
<item name="item_preferences">Tercihler</item>
<item name="item_password">Şifre Değiştir</item>
<item name="item_password">Hakkında</item>
<item name="item_share_app">uygulamayı Paylaş</item>
<item name="item_rate_us">Bizi değerlendirin</item>
<item name="item_password">Hakkında</item>
</string-array>
<!-- Regular information messages -->
......@@ -171,6 +173,13 @@
<string name="msg_view_less">Daha az göster</string>
<!-- TODO - Add proper translation -->
<string name="msg_permalink_copied">Permalink copied</string>
<!-- TODO - Add proper translation -->
<string name="msg_muted_on_this_channel">You are muted on this channel</string>
<!-- TODO - Add proper translation -->
<plurals name="msg_reacted_with_">
<item quantity="one">%1$s reacted with %2$s</item>
<item quantity="other">%1$s reacted with %2$s</item>
</plurals>
<!-- Preferences messages -->
<string name="msg_analytics_tracking">İstatistik takibi</string>
......
......@@ -16,6 +16,7 @@
<string name="title_settings">Налаштування</string>
<string name="title_preferences">Персональні</string>
<string name="title_change_password">Змінити пароль</string>
<string name="title_rate_us">Оцініть нас</string>
<string name="title_admin_panel">Панель адміністратора</string>
<string name="title_password">Змінити пароль</string>
<string name="title_update_profile">Оновити профіль</string>
......@@ -58,8 +59,9 @@
<string-array name="settings_actions">
<item name="item_preferences">Preferences</item> <!-- TODO Add translation -->
<item name="item_password">Change Password</item> <!-- TODO Add translation -->
<item name="item_password">About</item> <!-- TODO Add translation -->
<item name="item_share_app">поділитися прикладом</item>
<item name="item_rate_us">Оцініть нас</item>
<item name="item_password">About</item> <!-- TODO Add translation -->
</string-array>
<!-- Regular information messages -->
......@@ -156,6 +158,14 @@
<string name="msg_view_less">view less</string>
<!-- TODO - Add proper translation -->
<string name="msg_permalink_copied">Permalink copied</string>
<!-- TODO - Add proper translation -->
<string name="msg_muted_on_this_channel">You are muted on this channel</string>
<!-- TODO - Add proper translation -->
<plurals name="msg_reacted_with_">
<item quantity="one">%1$s reacted with %2$s</item>
<item quantity="few">%1$s reacted with %2$s</item>
<item quantity="many">%1$s reacted with %2$s</item>
</plurals>
<!-- Create channel messages -->
<string name="msg_private_channel">Приватний</string>
......
......@@ -5,4 +5,5 @@
<string name="community_server_url" translatable="false">open.rocket.chat</string>
<string name="create_server_url" translatable="false">cloud.rocket.chat/trial</string>
<string name="play_store_link" translatable="false">https://play.google.com/store/apps/details?id=chat.rocket.android</string>
<string name="market_link" translatable="false">market://details?id=chat.rocket.android</string>
</resources>
\ No newline at end of file
......@@ -28,6 +28,7 @@ https://github.com/RocketChat/java-code-styles/blob/master/CODING_STYLE.md#strin
<string name="title_settings">Settings</string>
<string name="title_preferences">Preferences</string>
<string name="title_change_password">Change Password</string>
<string name="title_rate_us">Rate Us</string>
<string name="title_admin_panel">Admin panel</string>
<string name="title_password">Change Password</string>
<string name="title_update_profile">Update profile</string>
......@@ -70,8 +71,9 @@ https://github.com/RocketChat/java-code-styles/blob/master/CODING_STYLE.md#strin
<string-array name="settings_actions">
<item name="item_preferences">Preferences</item>
<item name="item_password">Change Password</item>
<item name="item_password">About</item>
<item name="item_share_app">Share App</item>
<item name="item_rate_us">Rate Us</item>
<item name="item_password">About</item>
</string-array>
<!-- Regular information messages -->
......@@ -166,6 +168,10 @@ https://github.com/RocketChat/java-code-styles/blob/master/CODING_STYLE.md#strin
<string name="msg_two_factor_authentication">Two-factor Authentication</string>
<string name="msg__your_2fa_code">What’s your 2FA code?</string>
<string name="msg_permalink_copied">Permalink copied</string>
<plurals name="msg_reacted_with_">
<item quantity="one">%1$s reacted with %2$s</item>
<item quantity="other">%1$s reacted with %2$s</item>
</plurals>
<!-- Create channel messages -->
<string name="msg_private_channel">Private</string>
......@@ -183,6 +189,7 @@ https://github.com/RocketChat/java-code-styles/blob/master/CODING_STYLE.md#strin
<string name="msg_delete_description">Are you sure you want to delete this message</string>
<string name="msg_view_more">view more</string>
<string name="msg_view_less">view less</string>
<string name="msg_muted_on_this_channel">You are muted on this channel</string>
<!-- Preferences messages -->
<string name="msg_analytics_tracking">Analytics tracking</string>
......
......@@ -67,4 +67,11 @@ class AnswersAnalytics : Analytics {
)
override fun logOpenAdmin() = Answers.getInstance().logCustom(CustomEvent("open_admin"))
override fun logResetPassword(resetPasswordSucceeded: Boolean) =
Answers.getInstance()
.logCustom(
CustomEvent("reset_password")
.putCustomAttribute("resetPasswordSucceeded", resetPasswordSucceeded.toString())
)
}
......@@ -60,4 +60,9 @@ class GoogleAnalyticsForFirebase @Inject constructor(val context: Context) :
}
override fun logOpenAdmin() = firebaseAnalytics.logEvent("open_admin", null)
override fun logResetPassword(resetPasswordSucceeded: Boolean) =
firebaseAnalytics.logEvent("reset_password", Bundle(1).apply {
putBoolean("resetPasswordSucceeded", resetPasswordSucceeded)
})
}
package chat.rocket.android.push
import android.os.Bundle
import androidx.core.os.bundleOf
import androidx.work.Constraints
import androidx.work.NetworkType
......@@ -23,9 +24,12 @@ class FirebaseMessagingService : FirebaseMessagingService() {
}
override fun onMessageReceived(message: RemoteMessage) {
// XXX - for now this is ok, if we start to do network calls, use a Worker instead
message.data?.let {
pushManager.handle(bundleOf(*(it.map { Pair(it.key, it.value) }).toTypedArray()))
message.data?.let { data ->
val bundle = Bundle()
data.entries.forEach { entry ->
bundle.putString(entry.key, entry.value)
}
pushManager.handle(bundle)
}
}
......
......@@ -16,4 +16,14 @@ interface EmojiReactionListener {
* @param emojiShortname The shortname of the emoji (:grin:, :smiley:, etc).
*/
fun onReactionTouched(messageId: String, emojiShortname: String)
}
\ No newline at end of file
/**
* Callback when an added reaction is long-clicked.
*
* @param shortname The shortname of the emoji (:grin:, :smiley:, etc).
* @param isCustom Whether the reaction is custom or one of the defaults.
* @param url In case of a custom emoji, this is the url to find it. Can be null if not a custom.
* @param usernames The list of usernames of users who added the reaction.
*/
fun onReactionLongClicked(shortname: String, isCustom: Boolean, url: String?, usernames: List<String>)
}
<resources>
<string name="msg_no_recent_emoji">No recent emoji</string>
<string name="alert_title_default_skin_tone">Default skin tone</string>
<string name="msg_reactions" translatable="false">Reactions</string>
</resources>
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