Commit b2a55f2f authored by Govind Dixit's avatar Govind Dixit

fixes merge conflicts in (japanese)string.xml

parents 6d9868a4 644d6518
......@@ -23,10 +23,17 @@ class OnBoardingPresenter @Inject constructor(
private val getAccountsInteractor: GetAccountsInteractor,
val settingsInteractor: GetSettingsInteractor,
val factory: RocketChatClientFactory
) : CheckServerPresenter(strategy, factory, settingsInteractor) {
) : CheckServerPresenter(
strategy = strategy,
factory = factory,
settingsInteractor = settingsInteractor,
refreshSettingsInteractor = refreshSettingsInteractor
) {
fun toSignInToYourServer() = navigator.toSignInToYourServer()
fun toCreateANewServer(createServerUrl: String) = navigator.toWebPage(createServerUrl)
fun connectToCommunityServer(communityServerUrl: String) {
connectToServer(communityServerUrl) {
if (totalSocialAccountsEnabled == 0 && !isNewAccountCreationEnabled) {
......@@ -63,8 +70,6 @@ class OnBoardingPresenter @Inject constructor(
}
}
fun toCreateANewServer(createServerUrl: String) = navigator.toWebPage(createServerUrl)
private fun connectToServer(serverUrl: String, block: () -> Unit) {
launchUI(strategy) {
// Check if we already have an account for this server...
......@@ -77,9 +82,9 @@ class OnBoardingPresenter @Inject constructor(
try {
withContext(DefaultDispatcher) {
setupConnectionInfo(serverUrl)
refreshSettingsInteractor.refresh(serverUrl)
// preparing next fragment before showing it
refreshServerAccounts()
checkEnabledAccounts(serverUrl)
checkIfLoginFormIsEnabled()
checkIfCreateNewAccountIsEnabled()
......
......@@ -25,7 +25,13 @@ class ServerPresenter @Inject constructor(
private val getAccountsInteractor: GetAccountsInteractor,
val settingsInteractor: GetSettingsInteractor,
val factory: RocketChatClientFactory
) : CheckServerPresenter(strategy, factory, settingsInteractor, view) {
) : CheckServerPresenter(
strategy = strategy,
factory = factory,
settingsInteractor = settingsInteractor,
versionCheckView = view,
refreshSettingsInteractor = refreshSettingsInteractor
) {
fun checkServer(server: String) {
if (!server.isValidUrl()) {
......@@ -93,9 +99,8 @@ class ServerPresenter @Inject constructor(
view.showLoading()
try {
withContext(DefaultDispatcher) {
refreshSettingsInteractor.refresh(serverUrl)
// preparing next fragment before showing it
refreshServerAccounts()
checkEnabledAccounts(serverUrl)
checkIfLoginFormIsEnabled()
checkIfCreateNewAccountIsEnabled()
......@@ -112,5 +117,4 @@ class ServerPresenter @Inject constructor(
}
}
}
}
\ No newline at end of file
......@@ -38,6 +38,7 @@ 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.exhaustive
import chat.rocket.android.util.retryIO
import chat.rocket.common.RocketChatException
import chat.rocket.common.model.RoomType
......@@ -137,9 +138,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)
......
......@@ -770,9 +770,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
......
......@@ -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()
)
......@@ -56,7 +56,8 @@ class ChatRoomsPresenter @Inject constructor(
type = type.toString(),
name = username ?: name.toString(),
fullname = name.toString(),
open = open
open = open,
muted = muted
)
loadChatRoom(entity, false)
}
......
......@@ -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")
}
}
......@@ -41,13 +41,12 @@ import timber.log.Timber
import java.util.HashSet
import kotlin.system.measureTimeMillis
class DatabaseManager(val context: Application,
val serverUrl: String) {
class DatabaseManager(val context: Application, val serverUrl: String) {
private val database: RCDatabase = androidx.room.Room.databaseBuilder(context,
RCDatabase::class.java, serverUrl.databaseName())
.fallbackToDestructiveMigration()
.build()
RCDatabase::class.java, serverUrl.databaseName())
.fallbackToDestructiveMigration()
.build()
private val dbContext = newSingleThreadContext("$serverUrl-db-context")
private val dbManagerContext = newSingleThreadContext("$serverUrl-db-manager-context")
......@@ -124,11 +123,11 @@ class DatabaseManager(val context: Application,
val toInsert = ArrayList<ChatRoomEntity>(batch.size / 2)
val toUpdate = ArrayList<ChatRoomEntity>(batch.size)
batch.forEach {
when(it.type) {
when (it.type) {
is Type.Removed -> toRemove.add(removeChatRoom(it.data))
is Type.Inserted -> insertChatRoom(it.data)?.let { toInsert.add(it) }
is Type.Updated -> {
when(it.data) {
when (it.data) {
is Subscription -> updateSubs[(it.data as Subscription).roomId] = it.data as Subscription
is Room -> updateRooms[(it.data as Room).id] = it.data as Room
}
......@@ -154,10 +153,10 @@ class DatabaseManager(val context: Application,
launch(dbManagerContext) {
val user = userDao().getUser(myself.id)
val entity = user?.copy(
name = myself.name ?: user.name,
username = myself.username ?: user.username,
utcOffset = myself.utcOffset ?: user.utcOffset,
status = myself.status?.toString() ?: user.status
name = myself.name ?: user.name,
username = myself.username ?: user.username,
utcOffset = myself.utcOffset ?: user.utcOffset,
status = myself.status?.toString() ?: user.status
) ?: myself.asUser().toEntity()
Timber.d("UPDATING SELF: $entity")
......@@ -187,7 +186,7 @@ class DatabaseManager(val context: Application,
private suspend fun createMessageEntities(message: Message): Pair<MessageEntity, List<BaseMessageEntity>> {
val messageEntity = message.toEntity()
val list = mutableListOf<BaseMessageEntity>()
createAttachments(message)?.let { list.addAll(it) }
createAttachments(message)?.let { list.addAll(it) }
createFavoriteRelations(message)?.let { list.addAll(it) }
createMentionRelations(message)?.let { list.addAll(it) }
createChannelRelations(message)?.let { list.addAll(it) }
......@@ -225,7 +224,7 @@ class DatabaseManager(val context: Application,
val list = mutableListOf<UrlEntity>()
message.urls!!.forEach { url ->
list.add(UrlEntity(message.id, url.url, url.parsedUrl?.host, url.meta?.title,
url.meta?.description, url.meta?.imageUrl))
url.meta?.description, url.meta?.imageUrl))
}
return list
......@@ -329,7 +328,7 @@ class DatabaseManager(val context: Application,
}
private fun removeChatRoom(data: BaseRoom): String {
return when(data) {
return when (data) {
is Subscription -> data.roomId
else -> data.id
}
......@@ -344,14 +343,15 @@ class DatabaseManager(val context: Application,
insertUserIfMissing(user)
chatRoom.copy(
name = name ?: chatRoom.name,
fullname = fullName ?: chatRoom.fullname,
ownerId = user?.id ?: chatRoom.ownerId,
readonly = readonly,
updatedAt = updatedAt ?: chatRoom.updatedAt,
lastMessageText = mapLastMessageText(lastMessage),
lastMessageUserId = lastMessage?.sender?.id,
lastMessageTimestamp = lastMessage?.timestamp
name = name ?: chatRoom.name,
fullname = fullName ?: chatRoom.fullname,
ownerId = user?.id ?: chatRoom.ownerId,
readonly = readonly,
updatedAt = updatedAt ?: chatRoom.updatedAt,
lastMessageText = mapLastMessageText(lastMessage),
lastMessageUserId = lastMessage?.sender?.id,
lastMessageTimestamp = lastMessage?.timestamp,
muted = muted
)
}
}
......@@ -386,30 +386,32 @@ class DatabaseManager(val context: Application,
val chatRoom = current.chatRoom
chatRoom.copy(
id = roomId,
subscriptionId = id,
type = type.toString(),
name = name ?: throw NullPointerException(), // this should be filtered on the SDK
fullname = fullName ?: chatRoom.fullname,
userId = userId ?: chatRoom.userId,
readonly = readonly ?: chatRoom.readonly,
isDefault = isDefault,
favorite = isFavorite,
open = open,
alert = alert,
unread = unread,
userMentions = userMentions ?: chatRoom.userMentions,
groupMentions = groupMentions ?: chatRoom.groupMentions,
updatedAt = updatedAt ?: chatRoom.updatedAt,
timestamp = timestamp ?: chatRoom.timestamp,
lastSeen = lastSeen ?: chatRoom.lastSeen
id = roomId,
subscriptionId = id,
type = type.toString(),
name = name
?: throw NullPointerException(), // this should be filtered on the SDK
fullname = fullName ?: chatRoom.fullname,
userId = userId ?: chatRoom.userId,
readonly = readonly ?: chatRoom.readonly,
isDefault = isDefault,
favorite = isFavorite,
open = open,
alert = alert,
unread = unread,
userMentions = userMentions ?: chatRoom.userMentions,
groupMentions = groupMentions ?: chatRoom.groupMentions,
updatedAt = updatedAt ?: chatRoom.updatedAt,
timestamp = timestamp ?: chatRoom.timestamp,
lastSeen = lastSeen ?: chatRoom.lastSeen,
muted = chatRoom.muted
)
}
}
}
private suspend fun insertChatRoom(data: BaseRoom): ChatRoomEntity? {
return when(data) {
return when (data) {
is Room -> insertRoom(data)
is Subscription -> insertSubscription(data)
else -> null
......@@ -451,7 +453,8 @@ class DatabaseManager(val context: Application,
id = room.id,
subscriptionId = subscription.id,
type = room.type.toString(),
name = room.name ?: subscription.name ?: throw NullPointerException(), // this should be filtered on the SDK
name = room.name ?: subscription.name
?: throw NullPointerException(), // this should be filtered on the SDK
fullname = subscription.fullName ?: room.fullName,
userId = userId,
ownerId = room.user?.id,
......@@ -506,7 +509,8 @@ class DatabaseManager(val context: Application,
lastMessageText = mapLastMessageText(lastMessage),
lastMessageUserId = lastMessage?.sender?.id,
lastMessageTimestamp = lastMessage?.timestamp,
broadcast = broadcast
broadcast = broadcast,
muted = room.muted
)
}
}
......@@ -579,6 +583,7 @@ sealed class Operation {
val toUpdate: List<ChatRoomEntity>,
val toRemove: List<String>
) : Operation()
data class InsertRooms(val chatRooms: List<ChatRoomEntity>) : Operation()
data class CleanInsertRooms(val chatRooms: List<ChatRoomEntity>) : Operation()
......@@ -607,10 +612,10 @@ private fun Myself.asUser(): User {
private fun String.databaseName(): String {
val tmp = this.removePrefix("https://")
.removePrefix("http://")
.removeTrailingSlash()
.replace("/","-")
.replace(".", "_")
.removePrefix("http://")
.removeTrailingSlash()
.replace("/", "-")
.replace(".", "_")
return "$tmp.db"
}
\ No newline at end of file
......@@ -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
)
package chat.rocket.android.main.presentation
import android.content.Context
import chat.rocket.android.R
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.db.DatabaseManagerFactory
import chat.rocket.android.emoji.Emoji
......@@ -36,13 +35,9 @@ import chat.rocket.common.model.UserStatus
import chat.rocket.common.util.ifNull
import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.rest.getCustomEmojis
import chat.rocket.core.internal.rest.logout
import chat.rocket.core.internal.rest.me
import chat.rocket.core.internal.rest.unregisterPushToken
import chat.rocket.core.model.Myself
import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.channels.Channel
import kotlinx.coroutines.experimental.withContext
import timber.log.Timber
import javax.inject.Inject
......@@ -51,23 +46,33 @@ class MainPresenter @Inject constructor(
private val strategy: CancelStrategy,
private val navigator: MainNavigator,
private val tokenRepository: TokenRepository,
private val serverInteractor: GetCurrentServerInteractor,
private val refreshSettingsInteractor: RefreshSettingsInteractor,
private val refreshPermissionsInteractor: RefreshPermissionsInteractor,
private val localRepository: LocalRepository,
private val navHeaderMapper: NavHeaderUiModelMapper,
private val saveAccountInteractor: SaveAccountInteractor,
private val getAccountsInteractor: GetAccountsInteractor,
private val removeAccountInteractor: RemoveAccountInteractor,
factory: RocketChatClientFactory,
private val groupedPush: GroupedPush,
serverInteractor: GetCurrentServerInteractor,
localRepository: LocalRepository,
removeAccountInteractor: RemoveAccountInteractor,
factory: RocketChatClientFactory,
dbManagerFactory: DatabaseManagerFactory,
getSettingsInteractor: GetSettingsInteractor,
managerFactory: ConnectionManagerFactory
) : CheckServerPresenter(strategy, factory, view = view) {
) : CheckServerPresenter(
strategy = strategy,
factory = factory,
serverInteractor = serverInteractor,
localRepository = localRepository,
removeAccountInteractor = removeAccountInteractor,
tokenRepository = tokenRepository,
managerFactory = managerFactory,
dbManagerFactory = dbManagerFactory,
tokenView = view,
navigator = navigator
) {
private val currentServer = serverInteractor.get()!!
private val manager = managerFactory.create(currentServer)
private val dbManager = dbManagerFactory.create(currentServer)
private val client: RocketChatClient = factory.create(currentServer)
private var settings: PublicSettings = getSettingsInteractor.get(serverInteractor.get()!!)
private val userDataChannel = Channel<Myself>()
......@@ -114,9 +119,7 @@ class MainPresenter @Inject constructor(
view.setupUserAccountInfo(model)
} catch (ex: Exception) {
when (ex) {
is RocketChatAuthException -> {
logout()
}
is RocketChatAuthException -> logout()
else -> {
Timber.d(ex, "Error loading my information for navheader")
ex.message?.let {
......@@ -163,36 +166,9 @@ class MainPresenter @Inject constructor(
}
}
/**
* Logout from current server.
*/
fun logout() {
launchUI(strategy) {
view.showProgress()
try {
clearTokens()
retryIO("logout") { client.logout() }
} catch (exception: RocketChatException) {
Timber.d(exception, "Error calling logout")
exception.message?.let {
view.showMessage(it)
}.ifNull {
view.showGenericErrorMessage()
}
}
try {
disconnect()
removeAccountInteractor.remove(currentServer)
tokenRepository.remove(currentServer)
withContext(CommonPool) { dbManager.logout() }
navigator.switchOrAddNewServer()
} catch (ex: Exception) {
Timber.d(ex, "Error cleaning up the session...")
}
view.hideProgress()
}
setupConnectionInfo(currentServer)
super.logout(userDataChannel)
}
fun connect() {
......@@ -202,8 +178,8 @@ class MainPresenter @Inject constructor(
}
fun disconnect() {
manager.removeUserDataChannel(userDataChannel)
manager.disconnect()
setupConnectionInfo(currentServer)
super.disconnect(userDataChannel)
}
fun changeServer(serverUrl: String) {
......@@ -247,20 +223,6 @@ class MainPresenter @Inject constructor(
saveAccountInteractor.save(account)
}
private suspend fun clearTokens() {
serverInteractor.clear()
val pushToken = localRepository.get(LocalRepository.KEY_PUSH_TOKEN)
if (pushToken != null) {
try {
retryIO("unregisterPushToken") { client.unregisterPushToken(pushToken) }
view.invalidateToken(pushToken)
} catch (ex: Exception) {
Timber.d(ex, "Error unregistering push token")
}
}
localRepository.clearAllFromServer(currentServer)
}
private suspend fun subscribeMyselfUpdates() {
manager.addUserDataChannel(userDataChannel)
for (myself in userDataChannel) {
......
......@@ -4,9 +4,10 @@ import chat.rocket.android.authentication.server.presentation.VersionCheckView
import chat.rocket.android.core.behaviours.MessageView
import chat.rocket.android.main.uimodel.NavHeaderUiModel
import chat.rocket.android.server.domain.model.Account
import chat.rocket.android.server.presentation.TokenView
import chat.rocket.common.model.UserStatus
interface MainView : MessageView, VersionCheckView {
interface MainView : MessageView, VersionCheckView, TokenView {
/**
* Shows the current user status.
......@@ -31,8 +32,6 @@ interface MainView : MessageView, VersionCheckView {
fun closeServerSelection()
fun invalidateToken(token: String)
fun showProgress()
fun hideProgress()
......
......@@ -202,8 +202,7 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
.show()
}
override fun invalidateToken(token: String) =
invalidateFirebaseToken(token)
override fun invalidateToken(token: String) = invalidateFirebaseToken(token)
override fun showMessage(resId: Int) = showToast(resId)
......@@ -234,11 +233,11 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
fun showLogoutDialog() {
val builder = AlertDialog.Builder(this)
builder.setTitle(R.string.action_logout)
builder.setMessage(R.string.title_confirmation)
builder.setPositiveButton(R.string.action_logout) { _, _ -> presenter.logout()}
.setNegativeButton(R.string.action_stay) { dialog, _ -> dialog.cancel() }
builder.create().show()
builder.setTitle(R.string.title_are_you_sure)
.setPositiveButton(R.string.action_logout) { _, _ -> presenter.logout()}
.setNegativeButton(android.R.string.no) { dialog, _ -> dialog.cancel() }
.create()
.show()
}
fun setAvatar(avatarUrl: String) {
......
......@@ -5,19 +5,31 @@ import android.net.Uri
import chat.rocket.android.chatroom.domain.UriInteractor
import chat.rocket.android.core.behaviours.showMessage
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.db.DatabaseManagerFactory
import chat.rocket.android.helper.UserHelper
import chat.rocket.android.main.presentation.MainNavigator
import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.RemoveAccountInteractor
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.server.presentation.CheckServerPresenter
import chat.rocket.android.util.extension.compressImageAndGetByteArray
import chat.rocket.android.util.extension.gethash
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extension.toHex
import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.retryIO
import chat.rocket.common.RocketChatException
import chat.rocket.common.util.ifNull
import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.rest.deleteOwnAccount
import chat.rocket.core.internal.rest.resetAvatar
import chat.rocket.core.internal.rest.setAvatar
import chat.rocket.core.internal.rest.updateProfile
import kotlinx.coroutines.experimental.DefaultDispatcher
import kotlinx.coroutines.experimental.withContext
import java.lang.Exception
import java.util.*
import javax.inject.Inject
......@@ -26,8 +38,23 @@ class ProfilePresenter @Inject constructor(
private val strategy: CancelStrategy,
private val uriInteractor: UriInteractor,
val userHelper: UserHelper,
navigator: MainNavigator,
serverInteractor: GetCurrentServerInteractor,
factory: RocketChatClientFactory
factory: RocketChatClientFactory,
removeAccountInteractor: RemoveAccountInteractor,
tokenRepository: TokenRepository,
dbManagerFactory: DatabaseManagerFactory,
managerFactory: ConnectionManagerFactory
) : CheckServerPresenter(
strategy = strategy,
factory = factory,
serverInteractor = serverInteractor,
removeAccountInteractor = removeAccountInteractor,
tokenRepository = tokenRepository,
dbManagerFactory = dbManagerFactory,
managerFactory = managerFactory,
tokenView = view,
navigator = navigator
) {
private val serverUrl = serverInteractor.get()!!
private val client: RocketChatClient = factory.create(serverUrl)
......@@ -147,4 +174,27 @@ class ProfilePresenter @Inject constructor(
}
}
}
fun deleteAccount(password: String) {
launchUI(strategy) {
view.showLoading()
try {
withContext(DefaultDispatcher) {
// REMARK: Backend API is only working with a lowercase hash.
// https://github.com/RocketChat/Rocket.Chat/issues/12573
retryIO { client.deleteOwnAccount(password.gethash().toHex().toLowerCase()) }
setupConnectionInfo(serverUrl)
logout(null)
}
} catch (exception: Exception) {
exception.message?.let {
view.showMessage(it)
}.ifNull {
view.showGenericErrorMessage()
}
} finally {
view.hideLoading()
}
}
}
}
\ No newline at end of file
......@@ -2,8 +2,9 @@ package chat.rocket.android.profile.presentation
import chat.rocket.android.core.behaviours.LoadingView
import chat.rocket.android.core.behaviours.MessageView
import chat.rocket.android.server.presentation.TokenView
interface ProfileView : LoadingView, MessageView {
interface ProfileView : TokenView, LoadingView, MessageView {
/**
* Shows the user profile.
......
......@@ -2,6 +2,7 @@ package chat.rocket.android.profile.ui
import DrawableHelper
import android.app.Activity
import android.app.AlertDialog
import android.content.Intent
import android.graphics.Bitmap
import android.os.Build
......@@ -11,6 +12,8 @@ import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.view.MenuInflater
import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.ActionMode
import androidx.core.net.toUri
......@@ -29,6 +32,7 @@ import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.textContent
import chat.rocket.android.util.extensions.ui
import chat.rocket.android.util.invalidateFirebaseToken
import com.facebook.drawee.backends.pipeline.Fresco
import dagger.android.support.AndroidSupportInjection
import io.reactivex.disposables.CompositeDisposable
......@@ -61,6 +65,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
override fun onCreate(savedInstanceState: Bundle?) {
AndroidSupportInjection.inject(this)
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
}
override fun onCreateView(
......@@ -98,6 +103,25 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
}
}
override fun onPrepareOptionsMenu(menu: Menu) {
if (actionMode != null) {
menu.clear()
}
super.onPrepareOptionsMenu(menu)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
inflater.inflate(R.menu.profile, menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_delete_account -> showDeleteAccountDialog()
}
return true
}
override fun showProfile(avatarUrl: String, name: String, username: String, email: String?) {
ui {
image_avatar.setImageURI(avatarUrl)
......@@ -123,6 +147,8 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
showMessage(getString(R.string.msg_profile_update_successfully))
}
override fun invalidateToken(token: String) = invalidateFirebaseToken(token)
override fun showLoading() {
enableUserInput(false)
ui { view_loading.isVisible = true }
......@@ -148,7 +174,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error))
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
mode.menuInflater.inflate(R.menu.profile, menu)
mode.menuInflater.inflate(R.menu.action_mode_profile, menu)
mode.title = getString(R.string.title_update_profile)
return true
}
......@@ -239,6 +265,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
text_username.toString() != currentUsername ||
text_email.toString() != currentEmail)
}.subscribe { isValid ->
activity?.invalidateOptionsMenu()
if (isValid) {
startActionMode()
} else {
......@@ -264,4 +291,19 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
text_email.isEnabled = value
}
}
fun showDeleteAccountDialog() {
val passwordEditText = EditText(context)
passwordEditText.hint = getString(R.string.msg_password)
val builder = AlertDialog.Builder(context)
builder.setTitle(R.string.title_are_you_sure)
.setView(passwordEditText)
.setPositiveButton(R.string.action_delete_account) { _, _ ->
presenter.deleteAccount(passwordEditText.text.toString())
}
.setNegativeButton(android.R.string.no) { dialog, _ -> dialog.cancel() }
.create()
.show()
}
}
......@@ -3,7 +3,11 @@ package chat.rocket.android.server.presentation
import chat.rocket.android.BuildConfig
import chat.rocket.android.authentication.server.presentation.VersionCheckView
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.db.DatabaseManagerFactory
import chat.rocket.android.helper.OauthHelper
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.main.presentation.MainNavigator
import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.casLoginUrl
......@@ -18,6 +22,12 @@ import chat.rocket.android.server.domain.isLoginFormEnabled
import chat.rocket.android.server.domain.isRegistrationEnabledForNewUsers
import chat.rocket.android.server.domain.isWordpressAuthenticationEnabled
import chat.rocket.android.server.domain.wordpressUrl
import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.RemoveAccountInteractor
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.RefreshSettingsInteractor
import chat.rocket.android.server.infraestructure.ConnectionManager
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.VersionInfo
import chat.rocket.android.util.extension.launchUI
......@@ -30,9 +40,15 @@ import chat.rocket.common.RocketChatException
import chat.rocket.common.RocketChatInvalidProtocolException
import chat.rocket.common.model.ServerInfo
import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.rest.logout
import chat.rocket.core.internal.rest.serverInfo
import chat.rocket.core.internal.rest.settingsOauth
import chat.rocket.core.internal.rest.unregisterPushToken
import chat.rocket.core.model.Myself
import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.Job
import kotlinx.coroutines.experimental.channels.Channel
import kotlinx.coroutines.experimental.withContext
import timber.log.Timber
private const val SERVICE_NAME_FACEBOOK = "facebook"
......@@ -42,16 +58,26 @@ private const val SERVICE_NAME_LINKEDIN = "linkedin"
private const val SERVICE_NAME_GILAB = "gitlab"
private const val SERVICE_NAME_WORDPRESS = "wordpress"
abstract class CheckServerPresenter constructor(
private val strategy: CancelStrategy,
private val factory: RocketChatClientFactory,
private val settingsInteractor: GetSettingsInteractor? = null,
private val view: VersionCheckView? = null
private val serverInteractor: GetCurrentServerInteractor? = null,
private val localRepository: LocalRepository? = null,
private val removeAccountInteractor: RemoveAccountInteractor? = null,
private val tokenRepository: TokenRepository? = null,
private val managerFactory: ConnectionManagerFactory? = null,
private val dbManagerFactory: DatabaseManagerFactory? = null,
private val versionCheckView: VersionCheckView? = null,
private val tokenView: TokenView? = null,
private val navigator: MainNavigator? = null,
private val refreshSettingsInteractor: RefreshSettingsInteractor? = null
) {
private lateinit var currentServer: String
private lateinit var client: RocketChatClient
private lateinit var settings: PublicSettings
private lateinit var manager: ConnectionManager
private lateinit var dbManager: DatabaseManager
internal var state: String = ""
internal var facebookOauthUrl: String? = null
internal var githubOauthUrl: String? = null
......@@ -78,10 +104,22 @@ abstract class CheckServerPresenter constructor(
internal var isNewAccountCreationEnabled = false
internal fun setupConnectionInfo(serverUrl: String) {
settingsInteractor?.get(serverUrl)?.let {
currentServer = serverUrl
client = factory.create(serverUrl)
managerFactory?.create(serverUrl)?.let {
manager = it
}
dbManagerFactory?.create(serverUrl)?.let {
dbManager = it
}
}
internal suspend fun refreshServerAccounts() {
refreshSettingsInteractor?.refresh(currentServer)
settingsInteractor?.get(currentServer)?.let {
settings = it
}
client = factory.create(serverUrl)
state = ""
facebookOauthUrl = null
......@@ -117,28 +155,28 @@ abstract class CheckServerPresenter constructor(
client.serverInfo()
}
if (serverInfo.redirected) {
view?.updateServerUrl(serverInfo.url)
versionCheckView?.updateServerUrl(serverInfo.url)
}
val version = checkServerVersion(serverInfo)
when (version) {
is Version.VersionOk -> {
Timber.i("Your version is nice! (Requires: 0.62.0, Yours: ${version.version})")
view?.versionOk()
versionCheckView?.versionOk()
}
is Version.RecommendedVersionWarning -> {
Timber.i("Your server ${version.version} is bellow recommended version ${BuildConfig.RECOMMENDED_SERVER_VERSION}")
view?.alertNotRecommendedVersion()
versionCheckView?.alertNotRecommendedVersion()
}
is Version.OutOfDateError -> {
Timber.i("Oops. Looks like your server ${version.version} is out-of-date! Minimum server version required ${BuildConfig.REQUIRED_SERVER_VERSION}!")
view?.blockAndAlertNotRequiredVersion()
versionCheckView?.blockAndAlertNotRequiredVersion()
}
}
} catch (ex: Exception) {
Timber.d(ex, "Error getting server info")
when (ex) {
is RocketChatInvalidProtocolException -> view?.errorInvalidProtocol()
else -> view?.errorCheckingServerVersion()
is RocketChatInvalidProtocolException -> versionCheckView?.errorInvalidProtocol()
else -> versionCheckView?.errorCheckingServerVersion()
}
}
}
......@@ -162,8 +200,59 @@ abstract class CheckServerPresenter constructor(
}
}
private fun checkEnabledOauthAccounts(services: List<Map<String,Any>>, serverUrl: String) {
/**
* Logout the user from the current server.
*
* @param userDataChannel the user data channel to stop listening to changes (if currently subscribed).
*/
internal fun logout(userDataChannel: Channel<Myself>?) {
launchUI(strategy) {
try {
clearTokens()
retryIO("logout") { client.logout() }
} catch (exception: RocketChatException) {
Timber.e(exception, "Error calling logout")
}
try {
if (userDataChannel != null) {
disconnect(userDataChannel)
}
removeAccountInteractor?.remove(currentServer)
tokenRepository?.remove(currentServer)
withContext(CommonPool) { dbManager.logout() }
navigator?.switchOrAddNewServer()
} catch (ex: Exception) {
Timber.e(ex, "Error cleaning up the session...")
}
}
}
/**
* Stops listening to user data changes and disconnects the user.
*
* @param userDataChannel the user data channel to stop listening to changes.
*/
fun disconnect(userDataChannel: Channel<Myself>) {
manager.removeUserDataChannel(userDataChannel)
manager.disconnect()
}
private suspend fun clearTokens() {
serverInteractor?.clear()
val pushToken = localRepository?.get(LocalRepository.KEY_PUSH_TOKEN)
if (pushToken != null) {
try {
retryIO("unregisterPushToken") { client.unregisterPushToken(pushToken) }
tokenView?.invalidateToken(pushToken)
} catch (ex: Exception) {
Timber.e(ex, "Error unregistering push token")
}
}
localRepository?.clearAllFromServer(currentServer)
}
private fun checkEnabledOauthAccounts(services: List<Map<String,Any>>, serverUrl: String) {
if (settings.isFacebookAuthenticationEnabled()) {
getServiceMap(services, SERVICE_NAME_FACEBOOK)?.let { serviceMap ->
getOauthClientId(serviceMap)?.let { clientId ->
......@@ -552,4 +641,4 @@ abstract class CheckServerPresenter constructor(
data class OutOfDateError(private val currentVersion: String) : Version(currentVersion)
}
}
\ No newline at end of file
}
package chat.rocket.android.server.presentation
interface TokenView {
fun invalidateToken(token: String)
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/action_update_profile"
android:icon="@drawable/ic_check_white_24dp"
android:title="@string/action_update" />
</menu>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_update_profile"
android:icon="@drawable/ic_check_white_24dp"
android:title="@string/action_update" />
android:id="@+id/action_delete_account"
android:title="@string/action_delete_account"
app:showAsAction="never" />
</menu>
\ No newline at end of file
......@@ -22,7 +22,7 @@
<string name="title_update_profile">Update Profil</string>
<string name="title_about">Über</string>
<string name="title_create_channel">Erstelle Raum</string>
<string name="title_confirmation">Are You Sure you want to logout?</string><!-- TODO Add translation -->
<string name="title_are_you_sure">Are you sure?</string><!-- TODO Add translation -->
<!-- Actions -->
<string name="action_connect">Verbinde</string>
......@@ -35,7 +35,6 @@
<string name="action_create_channel">Erstelle Raum</string>
<string name="action_create">Erstelle</string>
<string name="action_logout">Abmelden</string>
<string name="action_stay">Stay</string> <!-- TODO Add translation -->
<string name="action_files">Dateien</string>
<string name="action_confirm_password">Bestätige Passwort Änderung</string>
<string name="action_join_chat">Trete Chat bei</string>
......@@ -54,6 +53,7 @@
<string name="action_create_server">Create a new server</string> <!-- TODO Add translation -->
<string name="action_register">Register</string> <!-- TODO Add translation -->
<string name="action_confirm">Confirm</string> <!-- TODO Add translation -->
<string name="action_delete_account">Delete account</string> <!-- TODO Add translation -->
<!-- Settings List -->
<string-array name="settings_actions">
......@@ -150,6 +150,8 @@
<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>
<!-- Create channel messages -->
<string name="msg_private_channel">Privat</string>
......
......@@ -21,7 +21,8 @@
<string name="title_update_profile">Actualización del perfil</string>
<string name="title_about">Acerca de</string>
<string name="title_create_channel">Crear canal</string>
<string name="title_confirmation">Are You Sure you want to logout?</string> <!-- TODO Add translation -->
<string name="title_are_you_sure">Are you sure?</string> <!-- TODO Add translation -->
<!-- Actions -->
<string name="action_connect">Conectar</string>
<string name="action_use_this_username">Usa este nombre de usuario</string>
......@@ -33,7 +34,6 @@
<string name="action_create_channel">Crear canal</string>
<string name="action_create">Create</string>
<string name="action_logout">Cerrar sesión</string>
<string name="action_stay">Stay</string> <!-- TODO Add translation -->
<string name="action_files">Archivos</string>
<string name="action_confirm_password">Confirmar cambio de contraseña</string>
<string name="action_join_chat">Unirse al chat</string>
......@@ -52,6 +52,7 @@
<string name="action_create_server">Create a new server</string> <!-- TODO Add translation -->
<string name="action_register">Register</string> <!-- TODO Add translation -->
<string name="action_confirm">Confirm</string> <!-- TODO Add translation -->
<string name="action_delete_account">Delete account</string> <!-- TODO Add translation -->
<!-- Settings List -->
<string-array name="settings_actions">
......@@ -167,6 +168,8 @@
<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>
<!-- Preferences messages -->
<string name="msg_analytics_tracking">Analytics tracking</string> <!-- TODO Add translation -->
......
......@@ -22,9 +22,7 @@
<string name="title_update_profile">Mettre à jour le profil</string>
<string name="title_about">À propos</string>
<string name="title_create_channel">Créer salon</string>
<string name="title_confirmation">Are You Sure you want to logout?</string> <!-- TODO Add translation -->
<string name="title_are_you_sure">Are you sure?</string> <!-- TODO Add translation -->
<!-- Actions -->
<string name="action_connect">Se connecter</string>
......@@ -37,7 +35,6 @@
<string name="action_create_channel">Créer salon</string>
<string name="action_create">Créer</string>
<string name="action_logout">Se déconnecter</string>
<string name="action_stay">Stay</string> <!-- TODO Add translation -->
<string name="action_files">Fichiers</string>
<string name="action_confirm_password">Confirmer le mot de passe</string>
<string name="action_join_chat">Rejoignez le chat</string>
......@@ -56,6 +53,7 @@
<string name="action_create_server">Create a new server</string> <!-- TODO Add translation -->
<string name="action_register">Register</string> <!-- TODO Add translation -->
<string name="action_confirm">Confirm</string> <!-- TODO Add translation -->
<string name="action_delete_account">Delete account</string> <!-- TODO Add translation -->
<!-- Settings List -->
<string-array name="settings_actions">
......@@ -162,6 +160,8 @@
<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>
<!-- Create channel messages -->
<string name="msg_private_channel">Privé</string>
......
......@@ -22,8 +22,7 @@
<string name="title_update_profile">प्रोफ़ाइल अपडेट करें</string>
<string name="title_about">परिचय</string>
<string name="title_create_channel">चैनल बनाएं</string>
<string name="title_confirmation">Are You Sure you want to logout?</string> <!-- TODO Add translation -->
<string name="title_are_you_sure">Are you sure?</string> <!-- TODO Add translation -->
<!-- Actions -->
<string name="action_connect">जुडिये</string>
......@@ -36,7 +35,6 @@
<string name="action_create_channel">चैनल बनाएं</string>
<string name="action_create">बनाएं</string>
<string name="action_logout">लोग आउट करें</string>
<string name="action_stay">Stay</string> <!-- TODO Add translation -->
<string name="action_files">फ़ाइलें</string>
<string name="action_confirm_password">पासवर्ड परिवर्तन की पुष्टि करें</string>
<string name="action_join_chat">चैट में शामिल हों</string>
......@@ -55,6 +53,7 @@
<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 -->
<!-- Settings List -->
<string-array name="settings_actions">
......@@ -173,6 +172,8 @@
<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>
<!-- Preferences messages -->
<string name="msg_analytics_tracking">एनालिटिक्स ट्रैकिंग</string>
......
......@@ -27,6 +27,7 @@
<string name="title_confirmation">ログアウトしますか?</string>
<!-- Actions -->
<string name="action_connect">接続</string>
<string name="action_use_this_username">このユーザー名を使用する</string>
......@@ -57,6 +58,7 @@
<string name="action_create_server">新規サーバーを作成</string>
<string name="action_register">登録</string>
<string name="action_confirm">確認</string>
<string name="action_delete_account">アカウントを削除する</string>
<!-- Settings List -->
<string-array name="settings_actions">
......@@ -156,10 +158,10 @@
<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>
<!-- Create channel messages -->
<string name="msg_private_channel">プライベート</string>
......@@ -213,7 +215,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 -->
......
......@@ -22,8 +22,7 @@
<string name="title_update_profile">Editar perfil</string>
<string name="title_about">Sobre</string>
<string name="title_create_channel">Criar chat</string>
<string name="title_confirmation">Are You Sure you want to logout?</string> <!-- TODO Add translation -->
<string name="title_are_you_sure">Você tem certeza?</string>
<!-- Actions -->
<string name="action_connect">Conectar</string>
......@@ -36,7 +35,6 @@
<string name="action_create_channel">Criar chat</string>
<string name="action_create">Criar</string>
<string name="action_logout">Sair</string>
<string name="action_stay">Stay</string> <!-- TODO Add translation -->
<string name="action_files">Arquivos</string>
<string name="action_confirm_password">Confirme a nova senha</string>
<string name="action_join_chat">Entrar no Chat</string>
......@@ -50,11 +48,12 @@
<string name="action_select_photo_from_gallery">Escolher foto da galeria</string>
<string name="action_take_photo">Tirar foto</string>
<string name="action_reset_avatar">Resetar avatar</string>
<string name="action_connect_server">Connect with a server</string> <!-- TODO Add translation -->
<string name="action_join_community">Join in the community</string> <!-- TODO Add translation -->
<string name="action_create_server">Create a new server</string> <!-- TODO Add translation -->
<string name="action_register">Register</string> <!-- TODO Add translation -->
<string name="action_confirm">Confirm</string> <!-- TODO Add translation -->
<string name="action_connect_server">Conectar com um servidor</string>
<string name="action_join_community">Junte-se à comunidade</string>
<string name="action_create_server">Criar um novo servidor</string>
<string name="action_register">Registrar</string>
<string name="action_confirm">Confirmar</string>
<string name="action_delete_account">Deletar conta</string>
<!-- Settings List -->
<string-array name="settings_actions">
......@@ -160,6 +159,7 @@
<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>
<!-- Create channel messages -->
<string name="msg_private_channel">Privado</string>
......@@ -188,8 +188,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.
......
......@@ -22,8 +22,7 @@
<string name="title_update_profile">Обновить профиль</string>
<string name="title_about">О программе</string>
<string name="title_create_channel">Создать новый канал</string>
<string name="title_confirmation">Вы действительно хотите выйти?</string>
<string name="title_are_you_sure">Are you sure?</string> <!-- TODO Add translation -->
<!-- Actions -->
<string name="action_connect">Подключиться</string>
......@@ -36,7 +35,6 @@
<string name="action_create_channel">Создать канал</string>
<string name="action_create">Создать</string>
<string name="action_logout">Выйти</string>
<string name="action_stay">Остаться</string>
<string name="action_files">Файлы</string>
<string name="action_confirm_password">Подтверждение изменения пароля</string>
<string name="action_join_chat">Присоединиться к чату</string>
......@@ -55,6 +53,7 @@
<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 -->
<!-- Settings List -->
<string-array name="settings_actions">
......@@ -157,6 +156,8 @@
<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>
<!-- Create channel messages -->
<string name="msg_private_channel">Приватный</string>
......
......@@ -22,8 +22,7 @@
<string name="title_update_profile">Profilinizi Düzenleyin</string>
<string name="title_about">Hakkında</string>
<string name="title_create_channel">Yeni Kanal Oluştur</string>
<string name="title_confirmation">Are You Sure you want to logout?</string> <!-- TODO Add translation -->
<string name="title_are_you_sure">Are you sure?</string> <!-- TODO Add translation -->
<!-- Actions -->
<string name="action_connect">Bağlan</string>
......@@ -36,7 +35,6 @@
<string name="action_create_channel">Yeni Kanal Oluştur</string>
<string name="action_create">Oluştur</string>
<string name="action_logout">Çıkış Yap</string>
<string name="action_stay">Stay</string> <!-- TODO Add translation -->
<string name="action_files">Dosyalar</string>
<string name="action_confirm_password">Şifre Değişikliğini Onaylayın</string>
<string name="action_join_chat">Sohbete Bağlan</string>
......@@ -55,6 +53,7 @@
<string name="action_create_server">Create a new server</string> <!-- TODO Add translation -->
<string name="action_register">Register</string> <!-- TODO Add translation -->
<string name="action_confirm">Confirm</string> <!-- TODO Add translation -->
<string name="action_delete_account">Delete account</string> <!-- TODO Add translation -->
<!-- Settings List -->
<string-array name="settings_actions">
......@@ -174,6 +173,8 @@
<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>
<!-- Preferences messages -->
<string name="msg_analytics_tracking">İstatistik takibi</string>
......
......@@ -22,8 +22,7 @@
<string name="title_update_profile">Оновити профіль</string>
<string name="title_about">"Про програму"</string>
<string name="title_create_channel">Створити новий канал</string>
<string name="title_confirmation">Are You Sure you want to logout?</string> <!-- TODO Add translation -->
<string name="title_are_you_sure">Are you sure?</string> <!-- TODO Add translation -->
<!-- Actions -->
<string name="action_connect">Підключитися</string>
......@@ -36,7 +35,6 @@
<string name="action_create_channel">Створити канал</string>
<string name="action_create">Створити</string>
<string name="action_logout">Вийти</string>
<string name="action_stay">Stay</string> <!-- TODO Add translation -->
<string name="action_files">Файли</string>
<string name="action_confirm_password">Підтвердження зміни пароля</string>
<string name="action_join_chat">Приєднатися до чату</string>
......@@ -55,6 +53,7 @@
<string name="action_create_server">Create a new server</string> <!-- TODO Add translation -->
<string name="action_register">Register</string> <!-- TODO Add translation -->
<string name="action_confirm">Confirm</string> <!-- TODO Add translation -->
<string name="action_delete_account">Delete account</string> <!-- TODO Add translation -->
<!-- Settings List -->
<string-array name="settings_actions">
......@@ -159,6 +158,8 @@
<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>
<!-- Create channel messages -->
<string name="msg_private_channel">Приватний</string>
......
......@@ -34,7 +34,7 @@ https://github.com/RocketChat/java-code-styles/blob/master/CODING_STYLE.md#strin
<string name="title_update_profile">Update profile</string>
<string name="title_about">About</string>
<string name="title_create_channel">Create Channel</string>
<string name="title_confirmation">Are You Sure you want to logout?</string>
<string name="title_are_you_sure">Are you sure?</string>
<!-- Actions -->
<string name="action_connect">Connect</string>
......@@ -47,7 +47,6 @@ https://github.com/RocketChat/java-code-styles/blob/master/CODING_STYLE.md#strin
<string name="action_create_channel">Create channel</string>
<string name="action_create">Create</string>
<string name="action_logout">Logout</string>
<string name="action_stay">Stay</string>
<string name="action_files">Files</string>
<string name="action_confirm_password">Confirm Password Change</string>
<string name="action_join_chat">Join Chat</string>
......@@ -66,6 +65,7 @@ https://github.com/RocketChat/java-code-styles/blob/master/CODING_STYLE.md#strin
<string name="action_create_server">Create a new server</string>
<string name="action_register">Register</string>
<string name="action_confirm">Confirm</string>
<string name="action_delete_account">Delete account</string>
<!-- Settings List -->
<string-array name="settings_actions">
......@@ -185,6 +185,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>
......
package chat.rocket.android.util.extension
import java.math.BigInteger
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException
@Throws(NoSuchAlgorithmException::class)
fun String.gethash(): ByteArray {
val digest = MessageDigest.getInstance("SHA-256")
digest.reset()
return digest.digest(this.toByteArray())
}
fun ByteArray.toHex(): String = String.format("%0" + this.size * 2 + "X", BigInteger(1, this))
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