Unverified Commit 0f142856 authored by Pitstopper's avatar Pitstopper Committed by GitHub

Merge branch 'beta' into patch-12

parents f5ad9216 18b506fe
...@@ -113,25 +113,26 @@ interface LoginOptionsView : LoadingView, MessageView { ...@@ -113,25 +113,26 @@ interface LoginOptionsView : LoadingView, MessageView {
// CAS account. // CAS account.
/** /**
* Shows the CAS button if the sign in/sign out via CAS protocol is enabled by the server * Adds a CAS button into accounts container.
* settings.
* *
* REMARK: We must set up the CAS button listener before showing it [setupCasButtonListener]. * @param casUrl The CAS url.
* @param casToken The CAS token
* @param serviceName The SAML service name.
* @param serviceNameColor The SAML service name color (just stylizing).
* @param buttonColor The SAML button color (just stylizing).
* @see [showAccountsView] * @see [showAccountsView]
*/ */
fun enableLoginByCas() fun addCasButton(
caslUrl: String,
/** casToken: String,
* Setups the CAS button. serviceName: String,
* serviceNameColor: Int,
* @param casUrl The CAS URL to authenticate with. buttonColor: Int
* @param casToken The requested token to be sent to the CAS server. )
*/
fun setupCasButtonListener(casUrl: String, casToken: String)
// Custom OAuth account. // Custom OAuth account.
/** /**
* Adds a custom OAuth button in the accounts container. * Adds a custom OAuth button into accounts container.
* *
* @customOauthUrl The custom OAuth url. * @customOauthUrl The custom OAuth url.
* @state A random string generated by the app, which you'll verify later * @state A random string generated by the app, which you'll verify later
...@@ -151,12 +152,13 @@ interface LoginOptionsView : LoadingView, MessageView { ...@@ -151,12 +152,13 @@ interface LoginOptionsView : LoadingView, MessageView {
// SAML account. // SAML account.
/** /**
* Adds a SAML button in the accounts container. * Adds a SAML button into accounts container.
* *
* @samlUrl The SAML url. * @param samlUrl The SAML url.
* @serviceName The SAML service name. * @param samlToken The SAML token.
* @serviceNameColor The SAML service name color (just stylizing). * @param serviceName The SAML service name.
* @buttonColor The SAML button color (just stylizing). * @param serviceNameColor The SAML service name color (just stylizing).
* @param buttonColor The SAML button color (just stylizing).
* @see [showAccountsView] * @see [showAccountsView]
*/ */
fun addSamlButton( fun addSamlButton(
......
...@@ -40,6 +40,9 @@ private const val GITLAB_OAUTH_URL = "gitlab_oauth_url" ...@@ -40,6 +40,9 @@ private const val GITLAB_OAUTH_URL = "gitlab_oauth_url"
private const val WORDPRESS_OAUTH_URL = "wordpress_oauth_url" private const val WORDPRESS_OAUTH_URL = "wordpress_oauth_url"
private const val CAS_LOGIN_URL = "cas_login_url" private const val CAS_LOGIN_URL = "cas_login_url"
private const val CAS_TOKEN = "cas_token" private const val CAS_TOKEN = "cas_token"
private const val CAS_SERVICE_NAME = "cas_service_name"
private const val CAS_SERVICE_NAME_TEXT_COLOR = "cas_service_name_text_color"
private const val CAS_SERVICE_BUTTON_COLOR = "cas_service_button_color"
private const val CUSTOM_OAUTH_URL = "custom_oauth_url" private const val CUSTOM_OAUTH_URL = "custom_oauth_url"
private const val CUSTOM_OAUTH_SERVICE_NAME = "custom_oauth_service_name" private const val CUSTOM_OAUTH_SERVICE_NAME = "custom_oauth_service_name"
private const val CUSTOM_OAUTH_SERVICE_NAME_TEXT_COLOR = "custom_oauth_service_name_text_color" private const val CUSTOM_OAUTH_SERVICE_NAME_TEXT_COLOR = "custom_oauth_service_name_text_color"
...@@ -69,6 +72,9 @@ fun newInstance( ...@@ -69,6 +72,9 @@ fun newInstance(
wordpressOauthUrl: String? = null, wordpressOauthUrl: String? = null,
casLoginUrl: String? = null, casLoginUrl: String? = null,
casToken: String? = null, casToken: String? = null,
casServiceName: String? = null,
casServiceNameTextColor: Int = 0,
casServiceButtonColor: Int = 0,
customOauthUrl: String? = null, customOauthUrl: String? = null,
customOauthServiceName: String? = null, customOauthServiceName: String? = null,
customOauthServiceNameTextColor: Int = 0, customOauthServiceNameTextColor: Int = 0,
...@@ -95,6 +101,9 @@ fun newInstance( ...@@ -95,6 +101,9 @@ fun newInstance(
putString(WORDPRESS_OAUTH_URL, wordpressOauthUrl) putString(WORDPRESS_OAUTH_URL, wordpressOauthUrl)
putString(CAS_LOGIN_URL, casLoginUrl) putString(CAS_LOGIN_URL, casLoginUrl)
putString(CAS_TOKEN, casToken) putString(CAS_TOKEN, casToken)
putString(CAS_SERVICE_NAME, casServiceName)
putInt(CAS_SERVICE_NAME_TEXT_COLOR, casServiceNameTextColor)
putInt(CAS_SERVICE_BUTTON_COLOR, casServiceButtonColor)
putString(CUSTOM_OAUTH_URL, customOauthUrl) putString(CUSTOM_OAUTH_URL, customOauthUrl)
putString(CUSTOM_OAUTH_SERVICE_NAME, customOauthServiceName) putString(CUSTOM_OAUTH_SERVICE_NAME, customOauthServiceName)
putInt(CUSTOM_OAUTH_SERVICE_NAME_TEXT_COLOR, customOauthServiceNameTextColor) putInt(CUSTOM_OAUTH_SERVICE_NAME_TEXT_COLOR, customOauthServiceNameTextColor)
...@@ -127,6 +136,9 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView { ...@@ -127,6 +136,9 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
private var wordpressOauthUrl: String? = null private var wordpressOauthUrl: String? = null
private var casLoginUrl: String? = null private var casLoginUrl: String? = null
private var casToken: String? = null private var casToken: String? = null
private var casServiceName: String? = null
private var casServiceNameTextColor: Int = 0
private var casServiceButtonColor: Int = 0
private var customOauthUrl: String? = null private var customOauthUrl: String? = null
private var customOauthServiceName: String? = null private var customOauthServiceName: String? = null
private var customOauthServiceTextColor: Int = 0 private var customOauthServiceTextColor: Int = 0
...@@ -157,6 +169,9 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView { ...@@ -157,6 +169,9 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
wordpressOauthUrl = bundle.getString(WORDPRESS_OAUTH_URL) wordpressOauthUrl = bundle.getString(WORDPRESS_OAUTH_URL)
casLoginUrl = bundle.getString(CAS_LOGIN_URL) casLoginUrl = bundle.getString(CAS_LOGIN_URL)
casToken = bundle.getString(CAS_TOKEN) casToken = bundle.getString(CAS_TOKEN)
casServiceName = bundle.getString(CAS_SERVICE_NAME)
casServiceNameTextColor = bundle.getInt(CAS_SERVICE_NAME_TEXT_COLOR)
casServiceButtonColor = bundle.getInt(CAS_SERVICE_BUTTON_COLOR)
customOauthUrl = bundle.getString(CUSTOM_OAUTH_URL) customOauthUrl = bundle.getString(CUSTOM_OAUTH_URL)
customOauthServiceName = bundle.getString(CUSTOM_OAUTH_SERVICE_NAME) customOauthServiceName = bundle.getString(CUSTOM_OAUTH_SERVICE_NAME)
customOauthServiceTextColor = bundle.getInt(CUSTOM_OAUTH_SERVICE_NAME_TEXT_COLOR) customOauthServiceTextColor = bundle.getInt(CUSTOM_OAUTH_SERVICE_NAME_TEXT_COLOR)
...@@ -200,6 +215,7 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView { ...@@ -200,6 +215,7 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
setupCas() setupCas()
setupCustomOauth() setupCustomOauth()
setupSaml() setupSaml()
setupAccountsView()
setupLoginWithEmailView() setupLoginWithEmailView()
setupCreateNewAccountView() setupCreateNewAccountView()
} }
...@@ -235,19 +251,17 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView { ...@@ -235,19 +251,17 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
setupWordpressButtonListener(wordpressOauthUrl.toString(), state.toString()) setupWordpressButtonListener(wordpressOauthUrl.toString(), state.toString())
enableLoginByWordpress() enableLoginByWordpress()
} }
if (totalSocialAccountsEnabled > 0) {
showAccountsView()
if (totalSocialAccountsEnabled > 3) {
setupExpandAccountsView()
}
}
} }
private fun setupCas() { private fun setupCas() {
if (casLoginUrl != null && casToken != null) { if (casLoginUrl != null && casToken != null && casServiceName != null) {
setupCasButtonListener(casLoginUrl.toString(), casToken.toString()) addCasButton(
enableLoginByCas() casLoginUrl.toString(),
casToken.toString(),
casServiceName.toString(),
casServiceNameTextColor,
casServiceButtonColor
)
} }
} }
...@@ -275,6 +289,15 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView { ...@@ -275,6 +289,15 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
} }
} }
private fun setupAccountsView() {
if (totalSocialAccountsEnabled > 0) {
showAccountsView()
if (totalSocialAccountsEnabled > 3) {
setupExpandAccountsView()
}
}
}
private fun setupLoginWithEmailView() { private fun setupLoginWithEmailView() {
if (isLoginFormEnabled) { if (isLoginFormEnabled) {
showLoginWithEmailButton() showLoginWithEmailButton()
...@@ -319,10 +342,17 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView { ...@@ -319,10 +342,17 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
setupButtonListener(button_wordpress, wordpressUrl, state, REQUEST_CODE_FOR_OAUTH) setupButtonListener(button_wordpress, wordpressUrl, state, REQUEST_CODE_FOR_OAUTH)
// CAS service account. // CAS service account.
override fun enableLoginByCas() = enableAccountButton(button_cas) override fun addCasButton(
caslUrl: String,
override fun setupCasButtonListener(casUrl: String, casToken: String) = casToken: String,
setupButtonListener(button_cas, casUrl, casToken, REQUEST_CODE_FOR_CAS) serviceName: String,
serviceNameColor: Int,
buttonColor: Int
) {
val button = getCustomServiceButton(serviceName, serviceNameColor, buttonColor)
setupButtonListener(button, caslUrl, casToken, REQUEST_CODE_FOR_CAS)
accounts_container.addView(button)
}
// Custom OAuth account. // Custom OAuth account.
override fun addCustomOauthButton( override fun addCustomOauthButton(
......
...@@ -43,6 +43,9 @@ class OnBoardingPresenter @Inject constructor( ...@@ -43,6 +43,9 @@ class OnBoardingPresenter @Inject constructor(
wordpressOauthUrl, wordpressOauthUrl,
casLoginUrl, casLoginUrl,
casToken, casToken,
casServiceName,
casServiceNameTextColor,
casServiceButtonColor,
customOauthUrl, customOauthUrl,
customOauthServiceName, customOauthServiceName,
customOauthServiceNameTextColor, customOauthServiceNameTextColor,
...@@ -73,9 +76,8 @@ class OnBoardingPresenter @Inject constructor( ...@@ -73,9 +76,8 @@ class OnBoardingPresenter @Inject constructor(
view.showLoading() view.showLoading()
try { try {
withContext(DefaultDispatcher) { withContext(DefaultDispatcher) {
refreshSettingsInteractor.refresh(serverUrl)
setupConnectionInfo(serverUrl) setupConnectionInfo(serverUrl)
refreshSettingsInteractor.refresh(serverUrl)
// preparing next fragment before showing it // preparing next fragment before showing it
checkEnabledAccounts(serverUrl) checkEnabledAccounts(serverUrl)
......
...@@ -30,6 +30,9 @@ class AuthenticationNavigator(internal val activity: AuthenticationActivity) { ...@@ -30,6 +30,9 @@ class AuthenticationNavigator(internal val activity: AuthenticationActivity) {
wordpressOauthUrl: String? = null, wordpressOauthUrl: String? = null,
casLoginUrl: String? = null, casLoginUrl: String? = null,
casToken: String? = null, casToken: String? = null,
casServiceName: String? = null,
casServiceNameTextColor: Int = 0,
casServiceButtonColor: Int = 0,
customOauthUrl: String? = null, customOauthUrl: String? = null,
customOauthServiceName: String? = null, customOauthServiceName: String? = null,
customOauthServiceNameTextColor: Int = 0, customOauthServiceNameTextColor: Int = 0,
...@@ -59,6 +62,9 @@ class AuthenticationNavigator(internal val activity: AuthenticationActivity) { ...@@ -59,6 +62,9 @@ class AuthenticationNavigator(internal val activity: AuthenticationActivity) {
wordpressOauthUrl, wordpressOauthUrl,
casLoginUrl, casLoginUrl,
casToken, casToken,
casServiceName,
casServiceNameTextColor,
casServiceButtonColor,
customOauthUrl, customOauthUrl,
customOauthServiceName, customOauthServiceName,
customOauthServiceNameTextColor, customOauthServiceNameTextColor,
......
...@@ -53,6 +53,9 @@ class ServerPresenter @Inject constructor( ...@@ -53,6 +53,9 @@ class ServerPresenter @Inject constructor(
wordpressOauthUrl, wordpressOauthUrl,
casLoginUrl, casLoginUrl,
casToken, casToken,
casServiceName,
casServiceNameTextColor,
casServiceButtonColor,
customOauthUrl, customOauthUrl,
customOauthServiceName, customOauthServiceName,
customOauthServiceNameTextColor, customOauthServiceNameTextColor,
...@@ -92,8 +95,6 @@ class ServerPresenter @Inject constructor( ...@@ -92,8 +95,6 @@ class ServerPresenter @Inject constructor(
withContext(DefaultDispatcher) { withContext(DefaultDispatcher) {
refreshSettingsInteractor.refresh(serverUrl) refreshSettingsInteractor.refresh(serverUrl)
setupConnectionInfo(serverUrl)
// preparing next fragment before showing it // preparing next fragment before showing it
checkEnabledAccounts(serverUrl) checkEnabledAccounts(serverUrl)
checkIfLoginFormIsEnabled() checkIfLoginFormIsEnabled()
......
...@@ -291,6 +291,9 @@ class ChatRoomAdapter( ...@@ -291,6 +291,9 @@ class ChatRoomAdapter(
R.id.action_menu_msg_react -> { R.id.action_menu_msg_react -> {
actionSelectListener?.showReactions(id) actionSelectListener?.showReactions(id)
} }
R.id.action_message_permalink -> {
actionSelectListener?.copyPermalink(id)
}
else -> { else -> {
TODO("Not implemented") TODO("Not implemented")
} }
...@@ -310,5 +313,6 @@ class ChatRoomAdapter( ...@@ -310,5 +313,6 @@ class ChatRoomAdapter(
fun showReactions(id: String) fun showReactions(id: String)
fun openDirectMessage(roomName: String, message: String) fun openDirectMessage(roomName: String, message: String)
fun sendMessage(chatRoomId: String, text: String) fun sendMessage(chatRoomId: String, text: String)
fun copyPermalink(id: String)
} }
} }
\ No newline at end of file
...@@ -35,6 +35,7 @@ import chat.rocket.android.server.domain.useRealName ...@@ -35,6 +35,7 @@ import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import chat.rocket.android.server.infraestructure.state import chat.rocket.android.server.infraestructure.state
import chat.rocket.android.util.extension.compressImageAndGetByteArray 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.extension.launchUI
import chat.rocket.android.util.extensions.avatarUrl import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.retryIO import chat.rocket.android.util.retryIO
...@@ -80,6 +81,7 @@ import kotlinx.coroutines.experimental.launch ...@@ -80,6 +81,7 @@ import kotlinx.coroutines.experimental.launch
import kotlinx.coroutines.experimental.withContext import kotlinx.coroutines.experimental.withContext
import org.threeten.bp.Instant import org.threeten.bp.Instant
import timber.log.Timber import timber.log.Timber
import java.io.InputStream
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
...@@ -346,15 +348,51 @@ class ChatRoomPresenter @Inject constructor( ...@@ -346,15 +348,51 @@ class ChatRoomPresenter @Inject constructor(
view.showFileSelection(settings.uploadMimeTypeFilter()) view.showFileSelection(settings.uploadMimeTypeFilter())
} }
fun uploadFile(roomId: String, uri: Uri, msg: String, bitmap: Bitmap? = null) { fun uploadImage(roomId: String, mimeType: String, uri: Uri, bitmap: Bitmap, msg: String) {
launchUI(strategy) { launchUI(strategy) {
view.showLoading() view.showLoading()
try { try {
withContext(DefaultDispatcher) { withContext(DefaultDispatcher) {
val fileName = uriInteractor.getFileName(uri) ?: uri.toString() val fileName = uriInteractor.getFileName(uri) ?: uri.toString()
val mimeType = uriInteractor.getMimeType(uri) if (fileName.isEmpty()) {
val byteArray = bitmap?.compressImageAndGetByteArray(mimeType) view.showInvalidFileMessage()
val fileSize = byteArray?.size ?: uriInteractor.getFileSize(uri) } else {
val byteArray =
bitmap.getByteArray(mimeType, 100, settings.uploadMaxFileSize())
retryIO("uploadFile($roomId, $fileName, $mimeType") {
client.uploadFile(
roomId,
fileName,
mimeType,
msg,
description = fileName
) {
byteArray.inputStream()
}
}
logMediaUploaded(mimeType)
}
}
} catch (ex: Exception) {
Timber.d(ex, "Error uploading image")
when (ex) {
is RocketChatException -> view.showMessage(ex)
else -> view.showGenericErrorMessage()
}
} finally {
view.hideLoading()
}
}
}
fun uploadFile(roomId: String, mimeType: String, uri: Uri, msg: String) {
launchUI(strategy) {
view.showLoading()
try {
withContext(DefaultDispatcher) {
val fileName = uriInteractor.getFileName(uri) ?: uri.toString()
val fileSize = uriInteractor.getFileSize(uri)
val maxFileSizeAllowed = settings.uploadMaxFileSize() val maxFileSizeAllowed = settings.uploadMaxFileSize()
when { when {
...@@ -370,7 +408,7 @@ class ChatRoomPresenter @Inject constructor( ...@@ -370,7 +408,7 @@ class ChatRoomPresenter @Inject constructor(
msg, msg,
description = fileName description = fileName
) { ) {
byteArray?.inputStream() ?: uriInteractor.getInputStream(uri) uriInteractor.getInputStream(uri)
} }
} }
logMediaUploaded(mimeType) logMediaUploaded(mimeType)
...@@ -503,7 +541,7 @@ class ChatRoomPresenter @Inject constructor( ...@@ -503,7 +541,7 @@ class ChatRoomPresenter @Inject constructor(
val messages = val messages =
retryIO(description = "history($chatRoomId, $roomType, $instant)") { retryIO(description = "history($chatRoomId, $roomType, $instant)") {
client.history( client.history(
chatRoomId, roomType, count = 50, chatRoomId, roomType, count = 50,
oldest = instant oldest = instant
) )
} }
...@@ -620,6 +658,7 @@ class ChatRoomPresenter @Inject constructor( ...@@ -620,6 +658,7 @@ class ChatRoomPresenter @Inject constructor(
try { try {
messagesRepository.getById(messageId)?.let { m -> messagesRepository.getById(messageId)?.let { m ->
view.copyToClipboard(m.message) view.copyToClipboard(m.message)
view.showMessage(R.string.msg_message_copied)
} }
} catch (e: RocketChatException) { } catch (e: RocketChatException) {
Timber.e(e) Timber.e(e)
...@@ -857,6 +896,42 @@ class ChatRoomPresenter @Inject constructor( ...@@ -857,6 +896,42 @@ 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
)
}
}
}
// TODO: move this to new interactor or FetchChatRoomsInteractor? // TODO: move this to new interactor or FetchChatRoomsInteractor?
private suspend fun getChatRoomsAsync(name: String? = null): List<ChatRoom> = withContext(CommonPool) { private suspend fun getChatRoomsAsync(name: String? = null): List<ChatRoom> = withContext(CommonPool) {
return@withContext dbManager.chatRoomDao().getAllSync().filter { return@withContext dbManager.chatRoomDao().getAllSync().filter {
...@@ -939,6 +1014,24 @@ class ChatRoomPresenter @Inject constructor( ...@@ -939,6 +1014,24 @@ class ChatRoomPresenter @Inject constructor(
} }
} }
fun copyPermalink(messageId: String) {
launchUI(strategy) {
try {
messagesRepository.getById(messageId)?.let { message ->
getChatRoomAsync(message.roomId)?.let { chatRoom ->
val models = mapper.map(message)
models.firstOrNull()?.permalink?.let {
view.copyToClipboard(it)
view.showMessage(R.string.msg_permalink_copied)
}
}
}
} catch (ex: Exception) {
Timber.e(ex)
}
}
}
/** /**
* Send an emoji reaction to a message. * Send an emoji reaction to a message.
*/ */
......
...@@ -621,7 +621,6 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -621,7 +621,6 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
ui { ui {
val clipboard = it.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager val clipboard = it.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
clipboard.primaryClip = ClipData.newPlainText("", message) clipboard.primaryClip = ClipData.newPlainText("", message)
showToast(R.string.msg_message_copied)
} }
} }
...@@ -1059,6 +1058,10 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -1059,6 +1058,10 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
} }
} }
override fun copyPermalink(id: String) {
presenter.copyPermalink(id)
}
override fun showReactions(id: String) { override fun showReactions(id: String) {
presenter.showReactions(id) presenter.showReactions(id)
} }
......
...@@ -7,7 +7,7 @@ import androidx.core.view.isVisible ...@@ -7,7 +7,7 @@ import androidx.core.view.isVisible
import chat.rocket.android.emoji.internal.GlideApp import chat.rocket.android.emoji.internal.GlideApp
import chat.rocket.android.util.extensions.getFileName import chat.rocket.android.util.extensions.getFileName
import chat.rocket.android.util.extensions.getMimeType import chat.rocket.android.util.extensions.getMimeType
import com.bumptech.glide.load.resource.gif.GifDrawable import chat.rocket.common.util.ifNull
import com.bumptech.glide.request.target.SimpleTarget import com.bumptech.glide.request.target.SimpleTarget
import com.bumptech.glide.request.transition.Transition import com.bumptech.glide.request.transition.Transition
...@@ -15,10 +15,12 @@ fun ChatRoomFragment.showFileAttachmentDialog(uri: Uri) { ...@@ -15,10 +15,12 @@ fun ChatRoomFragment.showFileAttachmentDialog(uri: Uri) {
imagePreview.isVisible = false imagePreview.isVisible = false
audioVideoAttachment.isVisible = false audioVideoAttachment.isVisible = false
textFile.isVisible = false textFile.isVisible = false
lateinit var mimeType: String
var bitmap: Bitmap? = null var bitmap: Bitmap? = null
activity?.let { context -> activity?.let { context ->
uri.getMimeType(context).let { mimeType -> uri.getMimeType(context).let {
mimeType = it
description.text.clear() description.text.clear()
when { when {
mimeType.startsWith("image") -> { mimeType.startsWith("image") -> {
...@@ -27,7 +29,6 @@ fun ChatRoomFragment.showFileAttachmentDialog(uri: Uri) { ...@@ -27,7 +29,6 @@ fun ChatRoomFragment.showFileAttachmentDialog(uri: Uri) {
.with(context) .with(context)
.asGif() .asGif()
.load(uri) .load(uri)
.override(imagePreview.width, imagePreview.height)
.fitCenter() .fitCenter()
.into(imagePreview) .into(imagePreview)
} else { } else {
...@@ -35,7 +36,6 @@ fun ChatRoomFragment.showFileAttachmentDialog(uri: Uri) { ...@@ -35,7 +36,6 @@ fun ChatRoomFragment.showFileAttachmentDialog(uri: Uri) {
.with(context) .with(context)
.asBitmap() .asBitmap()
.load(uri) .load(uri)
.override(imagePreview.width, imagePreview.height)
.fitCenter() .fitCenter()
.into(object : SimpleTarget<Bitmap>() { .into(object : SimpleTarget<Bitmap>() {
override fun onResourceReady( override fun onResourceReady(
...@@ -59,12 +59,22 @@ fun ChatRoomFragment.showFileAttachmentDialog(uri: Uri) { ...@@ -59,12 +59,22 @@ fun ChatRoomFragment.showFileAttachmentDialog(uri: Uri) {
} }
sendButton.setOnClickListener { sendButton.setOnClickListener {
presenter.uploadFile( bitmap?.let { bitmap ->
chatRoomId, presenter.uploadImage(
uri, chatRoomId,
(citation ?: "") + description.text.toString(), mimeType,
bitmap uri,
) bitmap,
(citation ?: "") + description.text.toString()
)
}.ifNull {
presenter.uploadFile(
chatRoomId,
mimeType,
uri,
(citation ?: "") + description.text.toString()
)
}
alertDialog.dismiss() alertDialog.dismiss()
} }
cancelButton.setOnClickListener { alertDialog.dismiss() } cancelButton.setOnClickListener { alertDialog.dismiss() }
......
...@@ -73,4 +73,4 @@ class MessageActionsBottomSheet : BottomSheetDialogFragment() { ...@@ -73,4 +73,4 @@ class MessageActionsBottomSheet : BottomSheetDialogFragment() {
} }
} }
} }
} }
\ No newline at end of file
...@@ -20,7 +20,8 @@ data class ActionsAttachmentUiModel( ...@@ -20,7 +20,8 @@ data class ActionsAttachmentUiModel(
override var unread: Boolean? = null, override var unread: Boolean? = null,
override var menuItemsToHide: MutableList<Int> = mutableListOf(), override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String, override var currentDayMarkerText: String,
override var showDayMarker: Boolean override var showDayMarker: Boolean,
override var permalink: String
) : BaseAttachmentUiModel<ActionsAttachment> { ) : BaseAttachmentUiModel<ActionsAttachment> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.ACTIONS_ATTACHMENT.viewType get() = BaseUiModel.ViewType.ACTIONS_ATTACHMENT.viewType
......
...@@ -5,20 +5,21 @@ import chat.rocket.core.model.Message ...@@ -5,20 +5,21 @@ import chat.rocket.core.model.Message
import chat.rocket.core.model.attachment.AudioAttachment import chat.rocket.core.model.attachment.AudioAttachment
data class AudioAttachmentUiModel( data class AudioAttachmentUiModel(
override val message: Message, override val message: Message,
override val rawData: AudioAttachment, override val rawData: AudioAttachment,
override val messageId: String, override val messageId: String,
override val attachmentUrl: String, override val attachmentUrl: String,
override val attachmentTitle: CharSequence, override val attachmentTitle: CharSequence,
override val id: Long, override val id: Long,
override var reactions: List<ReactionUiModel>, override var reactions: List<ReactionUiModel>,
override var nextDownStreamMessage: BaseUiModel<*>? = null, override var nextDownStreamMessage: BaseUiModel<*>? = null,
override var preview: Message? = null, override var preview: Message? = null,
override var isTemporary: Boolean = false, override var isTemporary: Boolean = false,
override var unread: Boolean? = null, override var unread: Boolean? = null,
override var menuItemsToHide: MutableList<Int> = mutableListOf(), override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String, override var currentDayMarkerText: String,
override var showDayMarker: Boolean override var showDayMarker: Boolean,
override var permalink: String
) : BaseFileAttachmentUiModel<AudioAttachment> { ) : BaseFileAttachmentUiModel<AudioAttachment> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.AUDIO_ATTACHMENT.viewType get() = BaseUiModel.ViewType.AUDIO_ATTACHMENT.viewType
......
...@@ -20,7 +20,7 @@ data class AuthorAttachmentUiModel( ...@@ -20,7 +20,7 @@ data class AuthorAttachmentUiModel(
override var unread: Boolean? = null, override var unread: Boolean? = null,
override var menuItemsToHide: MutableList<Int> = mutableListOf(), override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String, override var currentDayMarkerText: String,
override var showDayMarker: Boolean override var showDayMarker: Boolean, override var permalink: String
) : BaseAttachmentUiModel<AuthorAttachment> { ) : BaseAttachmentUiModel<AuthorAttachment> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.AUTHOR_ATTACHMENT.viewType get() = BaseUiModel.ViewType.AUTHOR_ATTACHMENT.viewType
......
...@@ -17,6 +17,7 @@ interface BaseUiModel<out T> { ...@@ -17,6 +17,7 @@ interface BaseUiModel<out T> {
var currentDayMarkerText: String var currentDayMarkerText: String
var showDayMarker: Boolean var showDayMarker: Boolean
var menuItemsToHide: MutableList<Int> var menuItemsToHide: MutableList<Int>
var permalink: String
enum class ViewType(val viewType: Int) { enum class ViewType(val viewType: Int) {
MESSAGE(0), MESSAGE(0),
......
...@@ -20,7 +20,8 @@ data class ColorAttachmentUiModel( ...@@ -20,7 +20,8 @@ data class ColorAttachmentUiModel(
override var unread: Boolean?, override var unread: Boolean?,
override var menuItemsToHide: MutableList<Int> = mutableListOf(), override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String, override var currentDayMarkerText: String,
override var showDayMarker: Boolean override var showDayMarker: Boolean,
override var permalink: String
) : BaseAttachmentUiModel<ColorAttachment> { ) : BaseAttachmentUiModel<ColorAttachment> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.COLOR_ATTACHMENT.viewType get() = BaseUiModel.ViewType.COLOR_ATTACHMENT.viewType
......
...@@ -18,7 +18,8 @@ data class GenericFileAttachmentUiModel( ...@@ -18,7 +18,8 @@ data class GenericFileAttachmentUiModel(
override var unread: Boolean? = null, override var unread: Boolean? = null,
override var menuItemsToHide: MutableList<Int> = mutableListOf(), override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String, override var currentDayMarkerText: String,
override var showDayMarker: Boolean override var showDayMarker: Boolean,
override var permalink: String
) : BaseFileAttachmentUiModel<GenericFileAttachment> { ) : BaseFileAttachmentUiModel<GenericFileAttachment> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.GENERIC_FILE_ATTACHMENT.viewType get() = BaseUiModel.ViewType.GENERIC_FILE_ATTACHMENT.viewType
......
...@@ -20,7 +20,8 @@ data class ImageAttachmentUiModel( ...@@ -20,7 +20,8 @@ data class ImageAttachmentUiModel(
override var unread: Boolean? = null, override var unread: Boolean? = null,
override var menuItemsToHide: MutableList<Int> = mutableListOf(), override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String, override var currentDayMarkerText: String,
override var showDayMarker: Boolean override var showDayMarker: Boolean,
override var permalink: String
) : BaseFileAttachmentUiModel<ImageAttachment> { ) : BaseFileAttachmentUiModel<ImageAttachment> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.IMAGE_ATTACHMENT.viewType get() = BaseUiModel.ViewType.IMAGE_ATTACHMENT.viewType
......
...@@ -19,7 +19,8 @@ data class MessageAttachmentUiModel( ...@@ -19,7 +19,8 @@ data class MessageAttachmentUiModel(
override var unread: Boolean? = null, override var unread: Boolean? = null,
override var menuItemsToHide: MutableList<Int> = mutableListOf(), override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String, override var currentDayMarkerText: String,
override var showDayMarker: Boolean override var showDayMarker: Boolean,
override var permalink: String
) : BaseUiModel<Message> { ) : BaseUiModel<Message> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.MESSAGE_ATTACHMENT.viewType get() = BaseUiModel.ViewType.MESSAGE_ATTACHMENT.viewType
......
...@@ -15,7 +15,8 @@ data class MessageReplyUiModel( ...@@ -15,7 +15,8 @@ data class MessageReplyUiModel(
override var unread: Boolean? = null, override var unread: Boolean? = null,
override var menuItemsToHide: MutableList<Int> = mutableListOf(), override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String, override var currentDayMarkerText: String,
override var showDayMarker: Boolean override var showDayMarker: Boolean,
override var permalink: String
) : BaseUiModel<MessageReply> { ) : BaseUiModel<MessageReply> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.MESSAGE_REPLY.viewType get() = BaseUiModel.ViewType.MESSAGE_REPLY.viewType
......
...@@ -20,7 +20,8 @@ data class MessageUiModel( ...@@ -20,7 +20,8 @@ data class MessageUiModel(
override var unread: Boolean? = null, override var unread: Boolean? = null,
var isFirstUnread: Boolean, var isFirstUnread: Boolean,
override var isTemporary: Boolean = false, override var isTemporary: Boolean = false,
override var menuItemsToHide: MutableList<Int> = mutableListOf() override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var permalink: String
) : BaseMessageUiModel<Message> { ) : BaseMessageUiModel<Message> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.MESSAGE.viewType get() = BaseUiModel.ViewType.MESSAGE.viewType
......
...@@ -131,23 +131,26 @@ class UiModelMapper @Inject constructor( ...@@ -131,23 +131,26 @@ class UiModelMapper @Inject constructor(
withContext(CommonPool) { withContext(CommonPool) {
val list = ArrayList<BaseUiModel<*>>() val list = ArrayList<BaseUiModel<*>>()
message.urls?.forEach { url -> getChatRoomAsync(message.roomId)?.let { chatRoom ->
mapUrl(message, url)?.let { list.add(it) } message.urls?.forEach { url ->
} mapUrl(message, url, chatRoom)?.let { list.add(it) }
}
message.attachments?.mapNotNull { attachment -> message.attachments?.mapNotNull { attachment ->
mapAttachment(message, attachment) mapAttachment(message, attachment, chatRoom)
}?.asReversed()?.let { }?.asReversed()?.let {
list.addAll(it) list.addAll(it)
} }
mapMessage(message).let { mapMessage(message, chatRoom).let {
if (list.isNotEmpty()) { if (list.isNotEmpty()) {
it.preview = list.first().preview it.preview = list.first().preview
}
list.add(it)
} }
list.add(it)
} }
for (i in list.size - 1 downTo 0) { for (i in list.size - 1 downTo 0) {
val next = if (i - 1 < 0) null else list[i - 1] val next = if (i - 1 < 0) null else list[i - 1]
list[i].nextDownStreamMessage = next list[i].nextDownStreamMessage = next
...@@ -214,24 +217,26 @@ class UiModelMapper @Inject constructor( ...@@ -214,24 +217,26 @@ class UiModelMapper @Inject constructor(
withContext(CommonPool) { withContext(CommonPool) {
val list = ArrayList<BaseUiModel<*>>() val list = ArrayList<BaseUiModel<*>>()
mapMessage(message).let { getChatRoomAsync(message.roomId)?.let { chatRoom ->
if (list.isNotEmpty()) { mapMessage(message, chatRoom).let {
it.preview = list.first().preview if (list.isNotEmpty()) {
it.preview = list.first().preview
}
list.add(it)
} }
list.add(it)
}
message.attachments?.forEach { message.attachments?.forEach {
val attachment = mapAttachment(message, it) val attachment = mapAttachment(message, it, chatRoom)
attachment?.let { attachment?.let {
list.add(attachment) list.add(attachment)
}
} }
}
message.urls?.forEach { message.urls?.forEach {
val url = mapUrl(message, it) val url = mapUrl(message, it, chatRoom)
url?.let { url?.let {
list.add(url) list.add(url)
}
} }
} }
...@@ -283,11 +288,12 @@ class UiModelMapper @Inject constructor( ...@@ -283,11 +288,12 @@ class UiModelMapper @Inject constructor(
nextDownStreamMessage = null, nextDownStreamMessage = null,
unread = message.unread, unread = message.unread,
currentDayMarkerText = dayMarkerText, currentDayMarkerText = dayMarkerText,
showDayMarker = false showDayMarker = false,
permalink = messageHelper.createPermalink(message, chatRoom, false)
) )
} }
private fun mapUrl(message: Message, url: Url): BaseUiModel<*>? { private fun mapUrl(message: Message, url: Url, chatRoom: ChatRoom): BaseUiModel<*>? {
if (url.ignoreParse || url.meta == null) return null if (url.ignoreParse || url.meta == null) return null
val hostname = url.parsedUrl?.hostname ?: "" val hostname = url.parsedUrl?.hostname ?: ""
...@@ -297,39 +303,53 @@ class UiModelMapper @Inject constructor( ...@@ -297,39 +303,53 @@ class UiModelMapper @Inject constructor(
val localDateTime = DateTimeHelper.getLocalDateTime(message.timestamp) val localDateTime = DateTimeHelper.getLocalDateTime(message.timestamp)
val dayMarkerText = DateTimeHelper.getFormattedDateForMessages(localDateTime, context) val dayMarkerText = DateTimeHelper.getFormattedDateForMessages(localDateTime, context)
val permalink = messageHelper.createPermalink(message, chatRoom, false)
return UrlPreviewUiModel(message, url, message.id, title, hostname, description, thumb, return UrlPreviewUiModel(message, url, message.id, title, hostname, description, thumb,
getReactions(message), preview = message.copy(message = url.url), unread = message.unread, getReactions(message), preview = message.copy(message = url.url), unread = message.unread,
showDayMarker = false, currentDayMarkerText = dayMarkerText) showDayMarker = false, currentDayMarkerText = dayMarkerText, permalink = permalink)
} }
private fun mapAttachment(message: Message, attachment: Attachment): BaseUiModel<*>? { private fun mapAttachment(
message: Message,
attachment: Attachment,
chatRoom: ChatRoom
): BaseUiModel<*>? {
return when (attachment) { return when (attachment) {
is FileAttachment -> mapFileAttachment(message, attachment) is FileAttachment -> mapFileAttachment(message, attachment, chatRoom)
is MessageAttachment -> mapMessageAttachment(message, attachment) is MessageAttachment -> mapMessageAttachment(message, attachment, chatRoom)
is AuthorAttachment -> mapAuthorAttachment(message, attachment) is AuthorAttachment -> mapAuthorAttachment(message, attachment, chatRoom)
is ColorAttachment -> mapColorAttachment(message, attachment) is ColorAttachment -> mapColorAttachment(message, attachment, chatRoom)
is ActionsAttachment -> mapActionsAttachment(message, attachment) is ActionsAttachment -> mapActionsAttachment(message, attachment, chatRoom)
else -> null else -> null
} }
} }
private fun mapActionsAttachment(message: Message, attachment: ActionsAttachment): BaseUiModel<*>? { private fun mapActionsAttachment(
message: Message,
attachment: ActionsAttachment,
chatRoom: ChatRoom
): BaseUiModel<*>? {
return with(attachment) { return with(attachment) {
val content = stripMessageQuotes(message) val content = stripMessageQuotes(message)
val localDateTime = DateTimeHelper.getLocalDateTime(message.timestamp) val localDateTime = DateTimeHelper.getLocalDateTime(message.timestamp)
val dayMarkerText = DateTimeHelper.getFormattedDateForMessages(localDateTime, context) val dayMarkerText = DateTimeHelper.getFormattedDateForMessages(localDateTime, context)
val permalink = messageHelper.createPermalink(message, chatRoom, false)
ActionsAttachmentUiModel(attachmentUrl = url, title = title, ActionsAttachmentUiModel(attachmentUrl = url, title = title,
actions = actions, buttonAlignment = buttonAlignment, message = message, rawData = attachment, actions = actions, buttonAlignment = buttonAlignment, message = message, rawData = attachment,
messageId = message.id, reactions = getReactions(message), messageId = message.id, reactions = getReactions(message),
preview = message.copy(message = content.message), unread = message.unread, preview = message.copy(message = content.message), unread = message.unread,
showDayMarker = false, currentDayMarkerText = dayMarkerText) showDayMarker = false, currentDayMarkerText = dayMarkerText, permalink = permalink)
} }
} }
private fun mapColorAttachment(message: Message, attachment: ColorAttachment): BaseUiModel<*>? { private fun mapColorAttachment(
message: Message,
attachment: ColorAttachment,
chatRoom: ChatRoom
): BaseUiModel<*>? {
return with(attachment) { return with(attachment) {
val content = stripMessageQuotes(message) val content = stripMessageQuotes(message)
val id = attachmentId(message, attachment) val id = attachmentId(message, attachment)
...@@ -337,12 +357,13 @@ class UiModelMapper @Inject constructor( ...@@ -337,12 +357,13 @@ class UiModelMapper @Inject constructor(
val localDateTime = DateTimeHelper.getLocalDateTime(message.timestamp) val localDateTime = DateTimeHelper.getLocalDateTime(message.timestamp)
val dayMarkerText = DateTimeHelper.getFormattedDateForMessages(localDateTime, context) val dayMarkerText = DateTimeHelper.getFormattedDateForMessages(localDateTime, context)
val fieldsText = mapFields(fields) val fieldsText = mapFields(fields)
val permalink = messageHelper.createPermalink(message, chatRoom, false)
ColorAttachmentUiModel(attachmentUrl = url, id = id, color = color.color, ColorAttachmentUiModel(attachmentUrl = url, id = id, color = color.color,
text = text, fields = fieldsText, message = message, rawData = attachment, text = text, fields = fieldsText, message = message, rawData = attachment,
messageId = message.id, reactions = getReactions(message), messageId = message.id, reactions = getReactions(message),
preview = message.copy(message = content.message), unread = message.unread, preview = message.copy(message = content.message), unread = message.unread,
showDayMarker = false, currentDayMarkerText = dayMarkerText) showDayMarker = false, currentDayMarkerText = dayMarkerText, permalink = permalink)
} }
} }
...@@ -364,7 +385,11 @@ class UiModelMapper @Inject constructor( ...@@ -364,7 +385,11 @@ class UiModelMapper @Inject constructor(
} }
} }
private fun mapAuthorAttachment(message: Message, attachment: AuthorAttachment): AuthorAttachmentUiModel { private fun mapAuthorAttachment(
message: Message,
attachment: AuthorAttachment,
chatRoom: ChatRoom
): AuthorAttachmentUiModel {
return with(attachment) { return with(attachment) {
val content = stripMessageQuotes(message) val content = stripMessageQuotes(message)
...@@ -373,16 +398,21 @@ class UiModelMapper @Inject constructor( ...@@ -373,16 +398,21 @@ class UiModelMapper @Inject constructor(
val localDateTime = DateTimeHelper.getLocalDateTime(message.timestamp) val localDateTime = DateTimeHelper.getLocalDateTime(message.timestamp)
val dayMarkerText = DateTimeHelper.getFormattedDateForMessages(localDateTime, context) val dayMarkerText = DateTimeHelper.getFormattedDateForMessages(localDateTime, context)
val permalink = messageHelper.createPermalink(message, chatRoom, false)
AuthorAttachmentUiModel(attachmentUrl = url, id = id, name = authorName, AuthorAttachmentUiModel(attachmentUrl = url, id = id, name = authorName,
icon = authorIcon, fields = fieldsText, message = message, rawData = attachment, icon = authorIcon, fields = fieldsText, message = message, rawData = attachment,
messageId = message.id, reactions = getReactions(message), messageId = message.id, reactions = getReactions(message),
preview = message.copy(message = content.message), unread = message.unread, preview = message.copy(message = content.message), unread = message.unread,
showDayMarker = false, currentDayMarkerText = dayMarkerText) showDayMarker = false, currentDayMarkerText = dayMarkerText, permalink = permalink)
} }
} }
private fun mapMessageAttachment(message: Message, attachment: MessageAttachment): MessageAttachmentUiModel { private fun mapMessageAttachment(
message: Message,
attachment: MessageAttachment,
chatRoom: ChatRoom
): MessageAttachmentUiModel {
val attachmentAuthor = attachment.author val attachmentAuthor = attachment.author
val time = attachment.timestamp?.let { getTime(it) } val time = attachment.timestamp?.let { getTime(it) }
val attachmentText = when (attachment.attachments.orEmpty().firstOrNull()) { val attachmentText = when (attachment.attachments.orEmpty().firstOrNull()) {
...@@ -397,15 +427,20 @@ class UiModelMapper @Inject constructor( ...@@ -397,15 +427,20 @@ class UiModelMapper @Inject constructor(
val dayMarkerText = DateTimeHelper.getFormattedDateForMessages(localDateTime, context) val dayMarkerText = DateTimeHelper.getFormattedDateForMessages(localDateTime, context)
val content = stripMessageQuotes(message) val content = stripMessageQuotes(message)
val permalink = messageHelper.createPermalink(message, chatRoom, false)
return MessageAttachmentUiModel(message = content, rawData = message, return MessageAttachmentUiModel(message = content, rawData = message,
messageId = message.id, time = time, senderName = attachmentAuthor, messageId = message.id, time = time, senderName = attachmentAuthor,
content = attachmentText, isPinned = message.pinned, reactions = getReactions(message), content = attachmentText, isPinned = message.pinned, reactions = getReactions(message),
preview = message.copy(message = content.message), unread = message.unread, preview = message.copy(message = content.message), unread = message.unread,
currentDayMarkerText = dayMarkerText, showDayMarker = false) currentDayMarkerText = dayMarkerText, showDayMarker = false, permalink = permalink)
} }
private fun mapFileAttachment(message: Message, attachment: FileAttachment): BaseUiModel<*>? { private fun mapFileAttachment(
message: Message,
attachment: FileAttachment,
chatRoom: ChatRoom
): BaseUiModel<*>? {
val attachmentUrl = attachmentUrl(attachment) val attachmentUrl = attachmentUrl(attachment)
val attachmentTitle = attachmentTitle(attachment) val attachmentTitle = attachmentTitle(attachment)
val attachmentText = attachmentText(attachment) val attachmentText = attachmentText(attachment)
...@@ -414,24 +449,25 @@ class UiModelMapper @Inject constructor( ...@@ -414,24 +449,25 @@ class UiModelMapper @Inject constructor(
val localDateTime = DateTimeHelper.getLocalDateTime(message.timestamp) val localDateTime = DateTimeHelper.getLocalDateTime(message.timestamp)
val dayMarkerText = DateTimeHelper.getFormattedDateForMessages(localDateTime, context) val dayMarkerText = DateTimeHelper.getFormattedDateForMessages(localDateTime, context)
val permalink = messageHelper.createPermalink(message, chatRoom, false)
return when (attachment) { return when (attachment) {
is ImageAttachment -> ImageAttachmentUiModel(message, attachment, message.id, is ImageAttachment -> ImageAttachmentUiModel(message, attachment, message.id,
attachmentUrl, attachmentTitle, attachmentText, attachmentDescription, id, getReactions(message), attachmentUrl, attachmentTitle, attachmentText, attachmentDescription, id, getReactions(message),
preview = message.copy(message = context.getString(R.string.msg_preview_photo)), unread = message.unread, preview = message.copy(message = context.getString(R.string.msg_preview_photo)), unread = message.unread,
showDayMarker = false, currentDayMarkerText = dayMarkerText) showDayMarker = false, currentDayMarkerText = dayMarkerText, permalink = permalink)
is VideoAttachment -> VideoAttachmentUiModel(message, attachment, message.id, is VideoAttachment -> VideoAttachmentUiModel(message, attachment, message.id,
attachmentUrl, attachmentTitle, id, getReactions(message), attachmentUrl, attachmentTitle, id, getReactions(message),
preview = message.copy(message = context.getString(R.string.msg_preview_video)), unread = message.unread, preview = message.copy(message = context.getString(R.string.msg_preview_video)), unread = message.unread,
showDayMarker = false, currentDayMarkerText = dayMarkerText) showDayMarker = false, currentDayMarkerText = dayMarkerText, permalink = permalink)
is AudioAttachment -> AudioAttachmentUiModel(message, attachment, message.id, is AudioAttachment -> AudioAttachmentUiModel(message, attachment, message.id,
attachmentUrl, attachmentTitle, id, getReactions(message), attachmentUrl, attachmentTitle, id, getReactions(message),
preview = message.copy(message = context.getString(R.string.msg_preview_audio)), unread = message.unread, preview = message.copy(message = context.getString(R.string.msg_preview_audio)), unread = message.unread,
showDayMarker = false, currentDayMarkerText = dayMarkerText) showDayMarker = false, currentDayMarkerText = dayMarkerText, permalink = permalink)
is GenericFileAttachment -> GenericFileAttachmentUiModel(message, attachment, is GenericFileAttachment -> GenericFileAttachmentUiModel(message, attachment,
message.id, attachmentUrl, attachmentTitle, id, getReactions(message), message.id, attachmentUrl, attachmentTitle, id, getReactions(message),
preview = message.copy(message = context.getString(R.string.msg_preview_file)), unread = message.unread, preview = message.copy(message = context.getString(R.string.msg_preview_file)), unread = message.unread,
showDayMarker = false, currentDayMarkerText = dayMarkerText) showDayMarker = false, currentDayMarkerText = dayMarkerText, permalink = permalink)
else -> null else -> null
} }
} }
...@@ -479,7 +515,10 @@ class UiModelMapper @Inject constructor( ...@@ -479,7 +515,10 @@ class UiModelMapper @Inject constructor(
return attachment.description return attachment.description
} }
private suspend fun mapMessage(message: Message): MessageUiModel = withContext(CommonPool) { private suspend fun mapMessage(
message: Message,
chatRoom: ChatRoom
): MessageUiModel = withContext(CommonPool) {
val sender = getSenderName(message) val sender = getSenderName(message)
val time = getTime(message.timestamp) val time = getTime(message.timestamp)
val avatar = getUserAvatar(message) val avatar = getUserAvatar(message)
...@@ -493,13 +532,14 @@ class UiModelMapper @Inject constructor( ...@@ -493,13 +532,14 @@ class UiModelMapper @Inject constructor(
val localDateTime = DateTimeHelper.getLocalDateTime(message.timestamp) val localDateTime = DateTimeHelper.getLocalDateTime(message.timestamp)
val dayMarkerText = DateTimeHelper.getFormattedDateForMessages(localDateTime, context) val dayMarkerText = DateTimeHelper.getFormattedDateForMessages(localDateTime, context)
val permalink = messageHelper.createPermalink(message, chatRoom, false)
val content = getContent(stripMessageQuotes(message)) val content = getContent(stripMessageQuotes(message))
MessageUiModel(message = stripMessageQuotes(message), rawData = message, MessageUiModel(message = stripMessageQuotes(message), rawData = message,
messageId = message.id, avatar = avatar!!, time = time, senderName = sender, messageId = message.id, avatar = avatar!!, time = time, senderName = sender,
content = content, isPinned = message.pinned, currentDayMarkerText = dayMarkerText, content = content, isPinned = message.pinned, currentDayMarkerText = dayMarkerText,
showDayMarker = false, reactions = getReactions(message), isFirstUnread = false, showDayMarker = false, reactions = getReactions(message), isFirstUnread = false,
preview = preview, isTemporary = !synced, unread = unread) preview = preview, isTemporary = !synced, unread = unread, permalink = permalink)
} }
private fun mapMessagePreview(message: Message): Message { private fun mapMessagePreview(message: Message): Message {
......
...@@ -19,7 +19,8 @@ data class UrlPreviewUiModel( ...@@ -19,7 +19,8 @@ data class UrlPreviewUiModel(
override var unread: Boolean? = null, override var unread: Boolean? = null,
override var menuItemsToHide: MutableList<Int> = mutableListOf(), override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String, override var currentDayMarkerText: String,
override var showDayMarker: Boolean override var showDayMarker: Boolean,
override var permalink: String
) : BaseUiModel<Url> { ) : BaseUiModel<Url> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.URL_PREVIEW.viewType get() = BaseUiModel.ViewType.URL_PREVIEW.viewType
......
...@@ -5,20 +5,21 @@ import chat.rocket.core.model.Message ...@@ -5,20 +5,21 @@ import chat.rocket.core.model.Message
import chat.rocket.core.model.attachment.VideoAttachment import chat.rocket.core.model.attachment.VideoAttachment
data class VideoAttachmentUiModel( data class VideoAttachmentUiModel(
override val message: Message, override val message: Message,
override val rawData: VideoAttachment, override val rawData: VideoAttachment,
override val messageId: String, override val messageId: String,
override val attachmentUrl: String, override val attachmentUrl: String,
override val attachmentTitle: CharSequence, override val attachmentTitle: CharSequence,
override val id: Long, override val id: Long,
override var reactions: List<ReactionUiModel>, override var reactions: List<ReactionUiModel>,
override var nextDownStreamMessage: BaseUiModel<*>? = null, override var nextDownStreamMessage: BaseUiModel<*>? = null,
override var preview: Message? = null, override var preview: Message? = null,
override var isTemporary: Boolean = false, override var isTemporary: Boolean = false,
override var unread: Boolean? = null, override var unread: Boolean? = null,
override var menuItemsToHide: MutableList<Int> = mutableListOf(), override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String, override var currentDayMarkerText: String,
override var showDayMarker: Boolean override var showDayMarker: Boolean,
override var permalink: String
) : BaseFileAttachmentUiModel<VideoAttachment> { ) : BaseFileAttachmentUiModel<VideoAttachment> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.VIDEO_ATTACHMENT.viewType get() = BaseUiModel.ViewType.VIDEO_ATTACHMENT.viewType
......
...@@ -2,7 +2,9 @@ package chat.rocket.android.chatroom.uimodel.suggestion ...@@ -2,7 +2,9 @@ package chat.rocket.android.chatroom.uimodel.suggestion
import chat.rocket.android.suggestions.model.SuggestionModel import chat.rocket.android.suggestions.model.SuggestionModel
class ChatRoomSuggestionUiModel(text: String, class ChatRoomSuggestionUiModel(
val fullName: String, text: String,
val name: String, val fullName: String,
searchList: List<String>) : SuggestionModel(text, searchList, false) val name: String,
\ No newline at end of file searchList: List<String>
) : SuggestionModel(text, searchList, false)
...@@ -2,6 +2,8 @@ package chat.rocket.android.chatroom.uimodel.suggestion ...@@ -2,6 +2,8 @@ package chat.rocket.android.chatroom.uimodel.suggestion
import chat.rocket.android.suggestions.model.SuggestionModel import chat.rocket.android.suggestions.model.SuggestionModel
class CommandSuggestionUiModel(text: String, class CommandSuggestionUiModel(
val description: String, text: String,
searchList: List<String>) : SuggestionModel(text, searchList) val description: String,
\ No newline at end of file searchList: List<String>
) : SuggestionModel(text, searchList)
\ No newline at end of file
...@@ -3,13 +3,15 @@ package chat.rocket.android.chatroom.uimodel.suggestion ...@@ -3,13 +3,15 @@ package chat.rocket.android.chatroom.uimodel.suggestion
import chat.rocket.android.suggestions.model.SuggestionModel import chat.rocket.android.suggestions.model.SuggestionModel
import chat.rocket.common.model.UserStatus import chat.rocket.common.model.UserStatus
class PeopleSuggestionUiModel(val imageUri: String?, class PeopleSuggestionUiModel(
text: String, val imageUri: String?,
val username: String, text: String,
val name: String, val username: String,
val status: UserStatus?, val name: String,
pinned: Boolean = false, val status: UserStatus?,
searchList: List<String>) : SuggestionModel(text, searchList, pinned) { pinned: Boolean = false,
searchList: List<String>
) : SuggestionModel(text, searchList, pinned) {
override fun toString(): String { override fun toString(): String {
return "PeopleSuggestionUiModel(imageUri='$imageUri', username='$username', name='$name', status=$status, pinned=$pinned)" return "PeopleSuggestionUiModel(imageUri='$imageUri', username='$username', name='$name', status=$status, pinned=$pinned)"
......
...@@ -17,7 +17,7 @@ class MessageHelper @Inject constructor( ...@@ -17,7 +17,7 @@ class MessageHelper @Inject constructor(
private val currentServer = serverInteractor.get()!! private val currentServer = serverInteractor.get()!!
private val settings: PublicSettings = getSettingsInteractor.get(currentServer) private val settings: PublicSettings = getSettingsInteractor.get(currentServer)
fun createPermalink(message: Message, chatRoom: ChatRoom): String { fun createPermalink(message: Message, chatRoom: ChatRoom, markdownSyntax: Boolean = true): String {
val type = when (chatRoom.type) { val type = when (chatRoom.type) {
is RoomType.PrivateGroup -> "group" is RoomType.PrivateGroup -> "group"
is RoomType.Channel -> "channel" is RoomType.Channel -> "channel"
...@@ -30,7 +30,8 @@ class MessageHelper @Inject constructor( ...@@ -30,7 +30,8 @@ class MessageHelper @Inject constructor(
} else { } else {
chatRoom.name chatRoom.name
} }
return "[ ]($currentServer/$type/$name?msg=${message.id}) " val permalink = "$currentServer/$type/$name?msg=${message.id}"
return if (markdownSyntax) "[ ]($permalink) " else permalink
} }
fun messageIdFromPermalink(permalink: String): String? { fun messageIdFromPermalink(permalink: String): String? {
......
...@@ -61,6 +61,9 @@ abstract class CheckServerPresenter constructor( ...@@ -61,6 +61,9 @@ abstract class CheckServerPresenter constructor(
internal var wordpressOauthUrl: String? = null internal var wordpressOauthUrl: String? = null
internal var casLoginUrl: String? = null internal var casLoginUrl: String? = null
internal var casToken: String? = null internal var casToken: String? = null
internal var casServiceName: String? = null
internal var casServiceNameTextColor: Int = 0
internal var casServiceButtonColor: Int = 0
internal var customOauthUrl: String? = null internal var customOauthUrl: String? = null
internal var customOauthServiceName: String? = null internal var customOauthServiceName: String? = null
internal var customOauthServiceNameTextColor: Int = 0 internal var customOauthServiceNameTextColor: Int = 0
...@@ -79,6 +82,31 @@ abstract class CheckServerPresenter constructor( ...@@ -79,6 +82,31 @@ abstract class CheckServerPresenter constructor(
settings = it settings = it
} }
client = factory.create(serverUrl) client = factory.create(serverUrl)
state = ""
facebookOauthUrl = null
githubOauthUrl = null
googleOauthUrl = null
linkedinOauthUrl = null
gitlabOauthUrl = null
wordpressOauthUrl = null
casLoginUrl = null
casToken = null
casServiceName = null
casServiceNameTextColor = 0
casServiceButtonColor = 0
customOauthUrl = null
customOauthServiceName = null
customOauthServiceNameTextColor = 0
customOauthServiceButtonColor= 0
samlUrl = null
samlToken = null
samlServiceName = null
samlServiceNameTextColor = 0
samlServiceButtonColor = 0
totalSocialAccountsEnabled = 0
isLoginFormEnabled = false
isNewAccountCreationEnabled = false
} }
internal fun checkServerInfo(serverUrl: String): Job { internal fun checkServerInfo(serverUrl: String): Job {
...@@ -125,7 +153,7 @@ abstract class CheckServerPresenter constructor( ...@@ -125,7 +153,7 @@ abstract class CheckServerPresenter constructor(
if (services.isNotEmpty()) { if (services.isNotEmpty()) {
state = OauthHelper.getState() state = OauthHelper.getState()
checkEnabledOauthAccounts(services, serverUrl) checkEnabledOauthAccounts(services, serverUrl)
checkEnabledCasAccounts(serverUrl) checkEnabledCasAccounts(services, serverUrl)
checkEnabledCustomOauthAccounts(services, serverUrl) checkEnabledCustomOauthAccounts(services, serverUrl)
checkEnabledSamlAccounts(services, serverUrl) checkEnabledSamlAccounts(services, serverUrl)
} }
...@@ -227,11 +255,25 @@ abstract class CheckServerPresenter constructor( ...@@ -227,11 +255,25 @@ abstract class CheckServerPresenter constructor(
} }
} }
private fun checkEnabledCasAccounts(serverUrl: String) { private fun checkEnabledCasAccounts(services: List<Map<String,Any>>, serverUrl: String) {
if (settings.isCasAuthenticationEnabled()) { if (settings.isCasAuthenticationEnabled()) {
casToken = generateRandomString(17) casToken = generateRandomString(17)
casLoginUrl = settings.casLoginUrl().casUrl(serverUrl, casToken.toString()) casLoginUrl = settings.casLoginUrl().casUrl(serverUrl, casToken.toString())
totalSocialAccountsEnabled++ getCasServices(services).let {
for (serviceMap in it) {
casServiceName = getServiceName(serviceMap)
val serviceNameTextColor = getServiceNameColor(serviceMap)
val serviceButtonColor = getServiceButtonColor(serviceMap)
if (casServiceName != null &&
serviceNameTextColor != null &&
serviceButtonColor != null
) {
casServiceNameTextColor = serviceNameTextColor
casServiceButtonColor = serviceButtonColor
totalSocialAccountsEnabled++
}
}
}
} }
} }
...@@ -244,8 +286,9 @@ abstract class CheckServerPresenter constructor( ...@@ -244,8 +286,9 @@ abstract class CheckServerPresenter constructor(
val clientId = getOauthClientId(serviceMap) val clientId = getOauthClientId(serviceMap)
val scope = getCustomOauthScope(serviceMap) val scope = getCustomOauthScope(serviceMap)
val serviceNameTextColor = val serviceNameTextColor =
getServiceNameColorForCustomOauthOrSaml(serviceMap) getServiceNameColor(serviceMap)
val serviceButtonColor = getServiceButtonColor(serviceMap) val serviceButtonColor = getServiceButtonColor(serviceMap)
if (customOauthServiceName != null && if (customOauthServiceName != null &&
host != null && host != null &&
authorizePath != null && authorizePath != null &&
...@@ -276,9 +319,9 @@ abstract class CheckServerPresenter constructor( ...@@ -276,9 +319,9 @@ abstract class CheckServerPresenter constructor(
samlToken = generateRandomString(17) samlToken = generateRandomString(17)
for (serviceMap in it) { for (serviceMap in it) {
val provider = getSamlProvider(serviceMap) val provider = getSamlProvider(serviceMap)
samlServiceName = getSamlServiceName(serviceMap) samlServiceName = getServiceName(serviceMap)
val serviceNameTextColor = val serviceNameTextColor =
getServiceNameColorForCustomOauthOrSaml(serviceMap) getServiceNameColor(serviceMap)
val serviceButtonColor = getServiceButtonColor(serviceMap) val serviceButtonColor = getServiceButtonColor(serviceMap)
if (provider != null && if (provider != null &&
...@@ -369,6 +412,14 @@ abstract class CheckServerPresenter constructor( ...@@ -369,6 +412,14 @@ abstract class CheckServerPresenter constructor(
private fun getCustomOauthServiceName(serviceMap: Map<String, Any>): String? = private fun getCustomOauthServiceName(serviceMap: Map<String, Any>): String? =
serviceMap["service"] as? String serviceMap["service"] as? String
/**
* Returns a CAS service list.
*
* @return A CAS service list, otherwise an empty list if there is no CAS service.
*/
private fun getCasServices(listMap: List<Map<String, Any>>): List<Map<String, Any>> =
listMap.filter { map -> map["service"] == "cas" }
/** /**
* Returns a SAML OAuth service list. * Returns a SAML OAuth service list.
* *
...@@ -388,26 +439,27 @@ abstract class CheckServerPresenter constructor( ...@@ -388,26 +439,27 @@ abstract class CheckServerPresenter constructor(
/** /**
* Returns the text of the SAML service. * Returns the text of the SAML service.
* REMARK: This can be used SAML or CAS.
* *
* @param serviceMap The service map to get the text of the SAML service. * @param serviceMap The service map to get the text of the SAML service.
* @return The text of the SAML service, otherwise null. * @return The text of the SAML service, otherwise null.
*/ */
private fun getSamlServiceName(serviceMap: Map<String, Any>): String? = private fun getServiceName(serviceMap: Map<String, Any>): String? =
serviceMap["buttonLabelText"] as? String serviceMap["buttonLabelText"] as? String
/** /**
* Returns the text color of the service name. * Returns the text color of the service name.
* REMARK: This can be used for custom OAuth or SAML. * REMARK: This can be used for custom OAuth, SAML or CAS.
* *
* @param serviceMap The service map to get the text color from. * @param serviceMap The service map to get the text color from.
* @return The text color of the service (custom OAuth or SAML), otherwise null. * @return The text color of the service (custom OAuth or SAML), otherwise null.
*/ */
private fun getServiceNameColorForCustomOauthOrSaml(serviceMap: Map<String, Any>): Int? = private fun getServiceNameColor(serviceMap: Map<String, Any>): Int? =
(serviceMap["buttonLabelColor"] as? String)?.parseColor() (serviceMap["buttonLabelColor"] as? String)?.parseColor()
/** /**
* Returns the button color of the service name. * Returns the button color of the service name.
* REMARK: This can be used for custom OAuth or SAML. * REMARK: This can be used for custom OAuth, SAML or CAS.
* *
* @param serviceMap The service map to get the button color from. * @param serviceMap The service map to get the button color from.
* @return The button color of the service (custom OAuth or SAML), otherwise null. * @return The button color of the service (custom OAuth or SAML), otherwise null.
......
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:fillColor="@color/actionMenuColor"
android:pathData="M9.548,14.23l-2.651,2.652a2.676,2.676 0,0 1,-3.78 0,2.676 2.676,0 0,1 0,-3.78L6.91,9.311a2.677,2.677 0,0 1,3.781 0,0.669 0.669,0 0,0 0.945,-0.946 4.015,4.015 0,0 0,-5.67 0l-3.792,3.792a4.014,4.014 0,0 0,0 5.67,4.014 4.014,0 0,0 5.67,0l2.65,-2.65a0.669,0.669 0,0 0,-0.945 -0.947zM17.828,2.173a4.014,4.014 0,0 0,-5.67 0L9.506,4.824a0.668,0.668 0,1 0,0.946 0.945l2.651,-2.651a2.676,2.676 0,0 1,3.78 0,2.676 2.676,0 0,1 0,3.78L13.09,10.69a2.678,2.678 0,0 1,-3.781 0,0.668 0.668,0 1,0 -0.945,0.945 4.015,4.015 0,0 0,5.67 0l3.793,-3.792a4.014,4.014 0,0 0,0 -5.67z" />
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp" android:width="108dp"
android:height="108dp" android:height="108dp"
android:viewportHeight="1055.0303" android:viewportWidth="247.7922"
android:viewportWidth="1055.0303"> android:viewportHeight="247.7922">
<group <group
android:translateX="281.28394" android:translateX="69.8961"
android:translateY="271.51514"> android:translateY="69.8961">
<path <path
android:fillColor="#FFDB2323" android:fillType="evenOdd"
android:pathData="M491.3,255.3c0,-24.1 -7.2,-47.2 -21.4,-68.7c-12.8,-19.3 -30.7,-36.4 -53.2,-50.7c-43.5,-27.8 -100.6,-43.1 -160.9,-43.1c-20.1,0 -40,1.7 -59.2,5.1c-11.9,-11.2 -25.9,-21.2 -40.7,-29.2c-79,-38.3 -144.6,-0.9 -144.6,-0.9s60.9,50.1 51,93.9c-27.3,27 -42,59.6 -42,93.6c0,0.1 0,0.2 0,0.3c0,0.1 0,0.2 0,0.3c0,33.9 14.8,66.6 42,93.6c9.9,43.9 -51,93.9 -51,93.9s65.5,37.4 144.6,-0.9c14.8,-8 28.8,-18 40.7,-29.2c19.2,3.4 39.1,5.1 59.2,5.1c60.3,0 117.4,-15.3 160.9,-43.1c22.5,-14.4 40.4,-31.5 53.2,-50.7c14.2,-21.5 21.4,-44.6 21.4,-68.7c0,-0.1 0,-0.2 0,-0.3C491.3,255.6 491.3,255.4 491.3,255.3z" /> android:pathData="M93.921,43.28L93.922,43.283C93.922,43.282 93.922,43.282 93.922,43.282C93.922,43.281 93.921,43.281 93.921,43.28ZM32.924,10.95C36.19,12.769 39.278,15.071 41.914,17.629C46.165,16.857 50.547,16.468 54.993,16.468C68.302,16.468 80.921,19.969 90.522,26.325C95.494,29.618 99.445,33.525 102.266,37.939C105.408,42.857 107,48.145 107,53.812C107,59.327 105.408,64.618 102.266,69.535C99.445,73.951 95.494,77.856 90.522,81.149C80.921,87.505 68.303,91.004 54.993,91.004C50.547,91.004 46.166,90.615 41.914,89.844C39.277,92.401 36.19,94.704 32.924,96.523C15.472,105.288 1,96.729 1,96.729C1,96.729 14.455,85.274 12.267,75.231C6.247,69.043 2.985,61.58 2.985,53.662C2.985,45.893 6.248,38.43 12.267,32.241C14.455,22.201 1.004,10.748 1,10.744C1.004,10.741 15.475,2.186 32.924,10.95Z"
android:strokeWidth="1"
android:strokeColor="#00000000">
<aapt:attr name="android:fillColor">
<gradient
android:endX="54"
android:endY="89.495674"
android:startX="54"
android:startY="-4.593772"
android:type="linear">
<item
android:color="#FFDB2323"
android:offset="0" />
<item
android:color="#FFDB2323"
android:offset="1" />
</gradient>
</aapt:attr>
</path>
<path <path
android:fillColor="#FFFFFF" android:fillColor="#FFFFFF"
android:pathData="M255.9,124.2c113.9,0 206.3,59 206.3,131.8c0,72.8 -92.4,131.8 -206.3,131.8c-25.4,0 -49.7,-2.9 -72.1,-8.3c-22.8,27.4 -73,65.6 -121.7,53.3c15.9,-17 39.4,-45.8 34.3,-93.2c-29.2,-22.7 -46.8,-51.8 -46.8,-83.5C49.6,183.2 142,124.2 255.9,124.2" /> android:fillType="nonZero"
android:pathData="M22.066,71.46C16.128,66.689 12.564,60.582 12.564,53.926C12.564,38.654 31.331,26.273 54.482,26.273C77.633,26.273 96.4,38.654 96.4,53.926C96.4,69.199 77.633,81.58 54.482,81.58C48.776,81.58 43.337,80.828 38.379,79.466L34.754,83.031C32.785,84.968 30.476,86.721 28.07,88.102C24.881,89.699 21.731,90.57 18.615,90.836C18.791,90.51 18.953,90.18 19.127,89.854C22.758,83.031 23.738,76.9 22.066,71.46Z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
<path <path
android:fillColor="#FFDB2323" android:fillType="nonZero"
android:pathData="M255.9,256m-27.4,0a27.4,27.4 0,1 1,54.8 0a27.4,27.4 0,1 1,-54.8 0" /> android:pathData="M35.209,53.736m-6.264,0a6.264,6.264 0,1 1,12.527 0a6.264,6.264 0,1 1,-12.527 0"
android:strokeWidth="1"
android:strokeColor="#00000000">
<aapt:attr name="android:fillColor">
<gradient
android:endX="35.2085"
android:endY="58.20792"
android:startX="35.2085"
android:startY="46.44125"
android:type="linear">
<item
android:color="#FFDB2323"
android:offset="0" />
<item
android:color="#FFDB2323"
android:offset="1" />
</gradient>
</aapt:attr>
</path>
<path <path
android:fillColor="#FFDB2323" android:fillType="nonZero"
android:pathData="M351.2,256m-27.4,0a27.4,27.4 0,1 1,54.8 0a27.4,27.4 0,1 1,-54.8 0" /> android:pathData="M54.482,53.736m-6.264,0a6.264,6.264 0,1 1,12.527 0a6.264,6.264 0,1 1,-12.527 0"
android:strokeWidth="1"
android:strokeColor="#00000000">
<aapt:attr name="android:fillColor">
<gradient
android:endX="54.4815"
android:endY="58.20792"
android:startX="54.4815"
android:startY="46.44125"
android:type="linear">
<item
android:color="#FFDB2323"
android:offset="0" />
<item
android:color="#FFDB2323"
android:offset="1" />
</gradient>
</aapt:attr>
</path>
<path <path
android:fillColor="#FFDB2323" android:fillType="nonZero"
android:pathData="M160.6,256m-27.4,0a27.4,27.4 0,1 1,54.8 0a27.4,27.4 0,1 1,-54.8 0" /> android:pathData="M75.682,53.736m-6.264,0a6.264,6.264 0,1 1,12.527 0a6.264,6.264 0,1 1,-12.527 0"
android:strokeWidth="1"
android:strokeColor="#00000000">
<aapt:attr name="android:fillColor">
<gradient
android:endX="75.6815"
android:endY="58.20792"
android:startX="75.6815"
android:startY="46.44125"
android:type="linear">
<item
android:color="#FFDB2323"
android:offset="0" />
<item
android:color="#FFDB2323"
android:offset="1" />
</gradient>
</aapt:attr>
</path>
</group> </group>
</vector> </vector>
\ No newline at end of file
...@@ -133,15 +133,6 @@ ...@@ -133,15 +133,6 @@
android:textSize="16sp" android:textSize="16sp"
android:visibility="gone" android:visibility="gone"
tools:visibility="visible" /> tools:visibility="visible" />
<Button
android:id="@+id/button_cas"
style="@style/Authentication.Button"
android:layout_marginTop="10dp"
android:clickable="false"
android:text="@string/action_login_or_sign_up"
android:visibility="gone"
tools:visibility="visible" />
</LinearLayout> </LinearLayout>
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
......
...@@ -12,6 +12,11 @@ ...@@ -12,6 +12,11 @@
android:icon="@drawable/ic_action_message_reply_24dp" android:icon="@drawable/ic_action_message_reply_24dp"
android:title="@string/action_msg_reply" /> android:title="@string/action_msg_reply" />
<item
android:id="@+id/action_message_permalink"
android:icon="@drawable/ic_action_message_link_24dp"
android:title="@string/action_msg_copy_permalink" />
<item <item
android:id="@+id/action_message_quote" android:id="@+id/action_message_quote"
android:icon="@drawable/ic_action_message_quote_24dp" android:icon="@drawable/ic_action_message_quote_24dp"
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
<!-- Actions --> <!-- Actions -->
<string name="action_connect">Verbinde</string> <string name="action_connect">Verbinde</string>
<string name="action_use_this_username">Benutze den Benutzernamen</string> <string name="action_use_this_username">Benutze den Benutzernamen</string>
<string name="action_login_or_sign_up">Klick diesen Knopf um sich anzumelden oder einen Account zu erstellen</string>
<string name="action_terms_of_service">Nutzungsbedingungen</string> <string name="action_terms_of_service">Nutzungsbedingungen</string>
<string name="action_privacy_policy">Datenschutz</string> <string name="action_privacy_policy">Datenschutz</string>
<string name="action_search">Suche</string> <string name="action_search">Suche</string>
...@@ -164,6 +163,8 @@ ...@@ -164,6 +163,8 @@
<string name="msg_view_more">view more</string> <string name="msg_view_more">view more</string>
<!-- TODO - Add proper translation --> <!-- TODO - Add proper translation -->
<string name="msg_view_less">view less</string> <string name="msg_view_less">view less</string>
<!-- TODO - Add proper translation -->
<string name="msg_permalink_copied">Permalink copied</string>
<!-- Preferences messages --> <!-- Preferences messages -->
<string name="msg_analytics_tracking">Analytics tracking</string> <!-- TODO Add translation --> <string name="msg_analytics_tracking">Analytics tracking</string> <!-- TODO Add translation -->
...@@ -200,6 +201,8 @@ ...@@ -200,6 +201,8 @@
<string name="action_msg_share">Teilen</string> <string name="action_msg_share">Teilen</string>
<string name="action_title_editing">Nachricht bearbeiten</string> <string name="action_title_editing">Nachricht bearbeiten</string>
<string name="action_msg_add_reaction">Reaktion hinzufügen</string> <string name="action_msg_add_reaction">Reaktion hinzufügen</string>
<!-- TODO - Add proper translation -->
<string name="action_msg_copy_permalink">Copy permalink</string>
<!-- Permission messages --> <!-- Permission messages -->
<string name="permission_editing_not_allowed">Bearbeiten nicht erlaubt</string> <string name="permission_editing_not_allowed">Bearbeiten nicht erlaubt</string>
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
<!-- Actions --> <!-- Actions -->
<string name="action_connect">Conectar</string> <string name="action_connect">Conectar</string>
<string name="action_use_this_username">Usa este nombre de usuario</string> <string name="action_use_this_username">Usa este nombre de usuario</string>
<string name="action_login_or_sign_up">Toca en este botón para iniciar sesión o crear una cuenta</string>
<string name="action_terms_of_service">Términos de Servicio</string> <string name="action_terms_of_service">Términos de Servicio</string>
<string name="action_privacy_policy">Política de Privacidad</string> <string name="action_privacy_policy">Política de Privacidad</string>
<string name="action_search">Buscar</string> <string name="action_search">Buscar</string>
...@@ -160,6 +159,8 @@ ...@@ -160,6 +159,8 @@
<string name="msg_view_more">view more</string> <string name="msg_view_more">view more</string>
<!-- TODO - Add proper translation --> <!-- TODO - Add proper translation -->
<string name="msg_view_less">view less</string> <string name="msg_view_less">view less</string>
<!-- TODO - Add proper translation -->
<string name="msg_permalink_copied">Permalink copied</string>
<!-- Preferences messages --> <!-- Preferences messages -->
<string name="msg_analytics_tracking">Analytics tracking</string> <!-- TODO Add translation --> <string name="msg_analytics_tracking">Analytics tracking</string> <!-- TODO Add translation -->
...@@ -196,6 +197,7 @@ ...@@ -196,6 +197,7 @@
<string name="action_msg_share">Compartir</string> <string name="action_msg_share">Compartir</string>
<string name="action_title_editing">Edición de mensaje</string> <string name="action_title_editing">Edición de mensaje</string>
<string name="action_msg_add_reaction">Añadir una reacción</string> <string name="action_msg_add_reaction">Añadir una reacción</string>
<string name="action_msg_copy_permalink">Copiar permalink</string>
<!-- Permission messages --> <!-- Permission messages -->
<string name="permission_editing_not_allowed">La edición no és permitida</string> <string name="permission_editing_not_allowed">La edición no és permitida</string>
......
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
<!-- Actions --> <!-- Actions -->
<string name="action_connect">Se connecter</string> <string name="action_connect">Se connecter</string>
<string name="action_use_this_username">Utilisez ce nom d\'utilisateur</string> <string name="action_use_this_username">Utilisez ce nom d\'utilisateur</string>
<string name="action_login_or_sign_up">Touchez ce bouton pour vous connecter ou créer un compte</string>
<string name="action_terms_of_service">Conditions d\'utilisation</string> <string name="action_terms_of_service">Conditions d\'utilisation</string>
<string name="action_privacy_policy">Politique de confidentialité</string> <string name="action_privacy_policy">Politique de confidentialité</string>
<string name="action_search">Chercher</string> <string name="action_search">Chercher</string>
...@@ -155,6 +154,8 @@ ...@@ -155,6 +154,8 @@
<string name="msg_view_more">view more</string> <string name="msg_view_more">view more</string>
<!-- TODO - Add proper translation --> <!-- TODO - Add proper translation -->
<string name="msg_view_less">view less</string> <string name="msg_view_less">view less</string>
<!-- TODO - Add proper translation -->
<string name="msg_permalink_copied">Permalink copied</string>
<!-- Create channel messages --> <!-- Create channel messages -->
<string name="msg_private_channel">Privé</string> <string name="msg_private_channel">Privé</string>
...@@ -204,6 +205,8 @@ ...@@ -204,6 +205,8 @@
<string name="action_msg_share">Partager</string> <string name="action_msg_share">Partager</string>
<string name="action_title_editing">Modification du message</string> <string name="action_title_editing">Modification du message</string>
<string name="action_msg_add_reaction">Ajouter une réaction</string> <string name="action_msg_add_reaction">Ajouter une réaction</string>
<!-- TODO - Add proper translation -->
<string name="action_msg_copy_permalink">Copy permalink</string>
<!-- Permission messages --> <!-- Permission messages -->
<string name="permission_editing_not_allowed">L\'édition n\'est pas autorisée</string> <string name="permission_editing_not_allowed">L\'édition n\'est pas autorisée</string>
......
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
<!-- Actions --> <!-- Actions -->
<string name="action_connect">जुडिये</string> <string name="action_connect">जुडिये</string>
<string name="action_use_this_username">इस उपयोगकर्ता नाम का उपयोग करें</string> <string name="action_use_this_username">इस उपयोगकर्ता नाम का उपयोग करें</string>
<string name="action_login_or_sign_up">लॉग इन करने या खाता बनाने के लिए इस बटन को टैप करें</string>
<string name="action_terms_of_service">सेवा की शर्तें</string> <string name="action_terms_of_service">सेवा की शर्तें</string>
<string name="action_privacy_policy">गोपनीयता नीति</string> <string name="action_privacy_policy">गोपनीयता नीति</string>
<string name="action_search">खोजें</string> <string name="action_search">खोजें</string>
...@@ -166,6 +165,8 @@ ...@@ -166,6 +165,8 @@
<string name="msg_channel_created_successfully">चैनल सफलतापूर्वक बनाया गया</string> <string name="msg_channel_created_successfully">चैनल सफलतापूर्वक बनाया गया</string>
<string name="msg_view_more">और देखें</string> <string name="msg_view_more">और देखें</string>
<string name="msg_view_less">कम देखें</string> <string name="msg_view_less">कम देखें</string>
<!-- TODO - Add proper translation -->
<string name="msg_permalink_copied">Permalink copied</string>
<!-- Preferences messages --> <!-- Preferences messages -->
<string name="msg_analytics_tracking">एनालिटिक्स ट्रैकिंग</string> <string name="msg_analytics_tracking">एनालिटिक्स ट्रैकिंग</string>
...@@ -188,7 +189,6 @@ ...@@ -188,7 +189,6 @@
<string name="message_role_removed">%1$s अब %3$s द्वारा %2$s नहीं है</string> <string name="message_role_removed">%1$s अब %3$s द्वारा %2$s नहीं है</string>
<string name="message_credentials_saved_successfully">प्रमाण पत्र सफलतापूर्वक सहेजे गए</string> <string name="message_credentials_saved_successfully">प्रमाण पत्र सफलतापूर्वक सहेजे गए</string>
<!-- Message actions --> <!-- Message actions -->
<string name="action_msg_reply">जवाब दें</string> <string name="action_msg_reply">जवाब दें</string>
<string name="action_msg_info">संदेश जानकारी</string> <string name="action_msg_info">संदेश जानकारी</string>
...@@ -203,6 +203,8 @@ ...@@ -203,6 +203,8 @@
<string name="action_msg_share">शेयर करें</string> <string name="action_msg_share">शेयर करें</string>
<string name="action_title_editing">संपादन संदेश</string> <string name="action_title_editing">संपादन संदेश</string>
<string name="action_msg_add_reaction">प्रतिक्रिया जोड़ें</string> <string name="action_msg_add_reaction">प्रतिक्रिया जोड़ें</string>
<!-- TODO - Add proper translation -->
<string name="action_msg_copy_permalink">Copy permalink</string>
<!-- Permission messages --> <!-- Permission messages -->
<string name="permission_editing_not_allowed">संपादन की अनुमति नहीं है</string> <string name="permission_editing_not_allowed">संपादन की अनुमति नहीं है</string>
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
<!-- Actions --> <!-- Actions -->
<string name="action_connect">接続</string> <string name="action_connect">接続</string>
<string name="action_use_this_username">このユーザー名を使用する</string> <string name="action_use_this_username">このユーザー名を使用する</string>
<string name="action_login_or_sign_up">ログインまたはアカウントを作成するにはこのボタンを押してください</string>
<string name="action_terms_of_service">サービス利用規約</string> <string name="action_terms_of_service">サービス利用規約</string>
<string name="action_privacy_policy">プライバシーポリシー</string> <string name="action_privacy_policy">プライバシーポリシー</string>
<string name="action_search">検索</string> <string name="action_search">検索</string>
...@@ -170,6 +169,8 @@ ...@@ -170,6 +169,8 @@
<string name="msg_message_copied">メッセージをコピー</string> <string name="msg_message_copied">メッセージをコピー</string>
<string name="msg_delete_message">メッセージを削除</string> <string name="msg_delete_message">メッセージを削除</string>
<string name="msg_delete_description">このメッセージを削除してもよろしいですか?</string> <string name="msg_delete_description">このメッセージを削除してもよろしいですか?</string>
<!-- TODO - Add proper translation -->
<string name="msg_permalink_copied">Permalink copied</string>
<!-- Preferences messages --> <!-- Preferences messages -->
<string name="msg_analytics_tracking">Analytics tracking</string> <!-- TODO Add translation --> <string name="msg_analytics_tracking">Analytics tracking</string> <!-- TODO Add translation -->
...@@ -206,6 +207,8 @@ ...@@ -206,6 +207,8 @@
<string name="action_msg_share">Share</string> <string name="action_msg_share">Share</string>
<string name="action_title_editing">メッセージの編集</string> <string name="action_title_editing">メッセージの編集</string>
<string name="action_msg_add_reaction">リアクションする</string> <string name="action_msg_add_reaction">リアクションする</string>
<!-- TODO - Add proper translation -->
<string name="action_msg_copy_permalink">Copy permalink</string>
<!-- Permission messages --> <!-- Permission messages -->
<string name="permission_editing_not_allowed">編集は許可されていません</string> <string name="permission_editing_not_allowed">編集は許可されていません</string>
......
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
<!-- Actions --> <!-- Actions -->
<string name="action_connect">Conectar</string> <string name="action_connect">Conectar</string>
<string name="action_use_this_username">Usar este nome de usuário</string> <string name="action_use_this_username">Usar este nome de usuário</string>
<string name="action_login_or_sign_up">Toque neste botão para fazer login ou criar uma conta</string>
<string name="action_terms_of_service">Termos de Serviço</string> <string name="action_terms_of_service">Termos de Serviço</string>
<string name="action_privacy_policy">Política de Privacidade</string> <string name="action_privacy_policy">Política de Privacidade</string>
<string name="action_search">Pesquisar</string> <string name="action_search">Pesquisar</string>
...@@ -153,6 +152,8 @@ ...@@ -153,6 +152,8 @@
<string name="msg__your_2fa_code">What’s your 2FA code?</string> <!-- TODO Add translation --> <string name="msg__your_2fa_code">What’s your 2FA code?</string> <!-- TODO Add translation -->
<string name="msg_view_more">visualizar mais</string> <string name="msg_view_more">visualizar mais</string>
<string name="msg_view_less">visualizar menos</string> <string name="msg_view_less">visualizar menos</string>
<!-- TODO - Add proper translation -->
<string name="msg_permalink_copied">Permalink copiado</string>
<!-- Create channel messages --> <!-- Create channel messages -->
<string name="msg_private_channel">Privado</string> <string name="msg_private_channel">Privado</string>
...@@ -202,6 +203,7 @@ ...@@ -202,6 +203,7 @@
<string name="action_msg_share">Compartilhar</string> <string name="action_msg_share">Compartilhar</string>
<string name="action_title_editing">Editando mensagem</string> <string name="action_title_editing">Editando mensagem</string>
<string name="action_msg_add_reaction">Adicionar reação</string> <string name="action_msg_add_reaction">Adicionar reação</string>
<string name="action_msg_copy_permalink">Copiar permalink</string>
<!-- Permission messages --> <!-- Permission messages -->
<string name="permission_editing_not_allowed">Edição não permitida</string> <string name="permission_editing_not_allowed">Edição não permitida</string>
......
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
<!-- Actions --> <!-- Actions -->
<string name="action_connect">Подключиться</string> <string name="action_connect">Подключиться</string>
<string name="action_use_this_username">Использовать это имя</string> <string name="action_use_this_username">Использовать это имя</string>
<string name="action_login_or_sign_up">Нажмите эту кнопку, чтобы войти в систему или создать учетную запись</string>
<string name="action_terms_of_service">Условия использования</string> <string name="action_terms_of_service">Условия использования</string>
<string name="action_privacy_policy">Политика конфиденциальности</string> <string name="action_privacy_policy">Политика конфиденциальности</string>
<string name="action_search">Поиск</string> <string name="action_search">Поиск</string>
...@@ -151,6 +150,8 @@ ...@@ -151,6 +150,8 @@
<string name="msg__your_2fa_code">Ваш код 2FA?</string> <string name="msg__your_2fa_code">Ваш код 2FA?</string>
<string name="msg_view_more">больше</string> <string name="msg_view_more">больше</string>
<string name="msg_view_less">меньше</string> <string name="msg_view_less">меньше</string>
<!-- TODO - Add proper translation -->
<string name="msg_permalink_copied">Permalink copied</string>
<!-- Create channel messages --> <!-- Create channel messages -->
<string name="msg_private_channel">Приватный</string> <string name="msg_private_channel">Приватный</string>
...@@ -199,6 +200,8 @@ ...@@ -199,6 +200,8 @@
<string name="action_msg_share">Поделиться</string> <string name="action_msg_share">Поделиться</string>
<string name="action_title_editing">Редактирование сообщения</string> <string name="action_title_editing">Редактирование сообщения</string>
<string name="action_msg_add_reaction">Отреагировать</string> <string name="action_msg_add_reaction">Отреагировать</string>
<!-- TODO - Add proper translation -->
<string name="action_msg_copy_permalink">Copy permalink</string>
<!-- Permission messages --> <!-- Permission messages -->
<string name="permission_editing_not_allowed">Редактирование запрещено</string> <string name="permission_editing_not_allowed">Редактирование запрещено</string>
......
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
<!-- Actions --> <!-- Actions -->
<string name="action_connect">Bağlan</string> <string name="action_connect">Bağlan</string>
<string name="action_use_this_username">Bu kullanıcı adını kullan</string> <string name="action_use_this_username">Bu kullanıcı adını kullan</string>
<string name="action_login_or_sign_up">Giriş yapmak veya yeni hesap oluşturmak için buraya tıklayın.</string>
<string name="action_terms_of_service">Kullanım Şartları</string> <string name="action_terms_of_service">Kullanım Şartları</string>
<string name="action_privacy_policy">Gizlilik Sözleşmesi</string> <string name="action_privacy_policy">Gizlilik Sözleşmesi</string>
<string name="action_search">Ara</string> <string name="action_search">Ara</string>
...@@ -167,6 +166,8 @@ ...@@ -167,6 +166,8 @@
<string name="msg_delete_description">Bu mesajı silmek istediğinizden emin misiniz</string> <string name="msg_delete_description">Bu mesajı silmek istediğinizden emin misiniz</string>
<string name="msg_view_more">Daha fazla göster</string> <string name="msg_view_more">Daha fazla göster</string>
<string name="msg_view_less">Daha az göster</string> <string name="msg_view_less">Daha az göster</string>
<!-- TODO - Add proper translation -->
<string name="msg_permalink_copied">Permalink copied</string>
<!-- Preferences messages --> <!-- Preferences messages -->
<string name="msg_analytics_tracking">İstatistik takibi</string> <string name="msg_analytics_tracking">İstatistik takibi</string>
...@@ -203,6 +204,8 @@ ...@@ -203,6 +204,8 @@
<string name="action_msg_share">Paylaş</string> <string name="action_msg_share">Paylaş</string>
<string name="action_title_editing">Mesaj Düzenleniyor</string> <string name="action_title_editing">Mesaj Düzenleniyor</string>
<string name="action_msg_add_reaction">Tepki Ekle</string> <string name="action_msg_add_reaction">Tepki Ekle</string>
<!-- TODO - Add proper translation -->
<string name="action_msg_copy_permalink">Copy permalink</string>
<!-- Permission messages --> <!-- Permission messages -->
<string name="permission_editing_not_allowed">Düzenlemeye izin verilmiyor</string> <string name="permission_editing_not_allowed">Düzenlemeye izin verilmiyor</string>
......
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
<!-- Actions --> <!-- Actions -->
<string name="action_connect">Підключитися</string> <string name="action_connect">Підключитися</string>
<string name="action_use_this_username">Використати це ім\'я</string> <string name="action_use_this_username">Використати це ім\'я</string>
<string name="action_login_or_sign_up">Натисніть цю кнопку, щоб увійти до системи або створити аккаунт</string>
<string name="action_terms_of_service">Умови використання</string> <string name="action_terms_of_service">Умови використання</string>
<string name="action_privacy_policy">Політика конфіденційності</string> <string name="action_privacy_policy">Політика конфіденційності</string>
<string name="action_search">Пошук</string> <string name="action_search">Пошук</string>
...@@ -152,6 +151,8 @@ ...@@ -152,6 +151,8 @@
<string name="msg_view_more">view more</string> <string name="msg_view_more">view more</string>
<!-- TODO - Add proper translation --> <!-- TODO - Add proper translation -->
<string name="msg_view_less">view less</string> <string name="msg_view_less">view less</string>
<!-- TODO - Add proper translation -->
<string name="msg_permalink_copied">Permalink copied</string>
<!-- Create channel messages --> <!-- Create channel messages -->
<string name="msg_private_channel">Приватний</string> <string name="msg_private_channel">Приватний</string>
...@@ -200,6 +201,8 @@ ...@@ -200,6 +201,8 @@
<string name="action_msg_share">Поділитися</string> <string name="action_msg_share">Поділитися</string>
<string name="action_title_editing">Редагування повідомлення</string> <string name="action_title_editing">Редагування повідомлення</string>
<string name="action_msg_add_reaction">Відреагувати</string> <string name="action_msg_add_reaction">Відреагувати</string>
<!-- TODO - Add proper translation -->
<string name="action_msg_copy_permalink">Copy permalink</string>
<!-- Permission messages --> <!-- Permission messages -->
<string name="permission_editing_not_allowed">Редагування заборонено</string> <string name="permission_editing_not_allowed">Редагування заборонено</string>
......
...@@ -37,7 +37,6 @@ https://github.com/RocketChat/java-code-styles/blob/master/CODING_STYLE.md#strin ...@@ -37,7 +37,6 @@ https://github.com/RocketChat/java-code-styles/blob/master/CODING_STYLE.md#strin
<!-- Actions --> <!-- Actions -->
<string name="action_connect">Connect</string> <string name="action_connect">Connect</string>
<string name="action_use_this_username">Use this username</string> <string name="action_use_this_username">Use this username</string>
<string name="action_login_or_sign_up">Tap this button to log in or create an account</string>
<string name="action_terms_of_service">Terms of Service</string> <string name="action_terms_of_service">Terms of Service</string>
<string name="action_privacy_policy">Privacy Policy</string> <string name="action_privacy_policy">Privacy Policy</string>
<string name="action_search">Search</string> <string name="action_search">Search</string>
...@@ -162,6 +161,7 @@ https://github.com/RocketChat/java-code-styles/blob/master/CODING_STYLE.md#strin ...@@ -162,6 +161,7 @@ https://github.com/RocketChat/java-code-styles/blob/master/CODING_STYLE.md#strin
<string name="msg_continue_with_wordpress">Continue with <b>WordPress</b></string> <string name="msg_continue_with_wordpress">Continue with <b>WordPress</b></string>
<string name="msg_two_factor_authentication">Two-factor Authentication</string> <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__your_2fa_code">What’s your 2FA code?</string>
<string name="msg_permalink_copied">Permalink copied</string>
<!-- Create channel messages --> <!-- Create channel messages -->
<string name="msg_private_channel">Private</string> <string name="msg_private_channel">Private</string>
...@@ -215,6 +215,7 @@ https://github.com/RocketChat/java-code-styles/blob/master/CODING_STYLE.md#strin ...@@ -215,6 +215,7 @@ https://github.com/RocketChat/java-code-styles/blob/master/CODING_STYLE.md#strin
<string name="action_msg_share">Share</string> <string name="action_msg_share">Share</string>
<string name="action_title_editing">Editing Message</string> <string name="action_title_editing">Editing Message</string>
<string name="action_msg_add_reaction">Add reaction</string> <string name="action_msg_add_reaction">Add reaction</string>
<string name="action_msg_copy_permalink">Copy permalink</string>
<!-- Permission messages --> <!-- Permission messages -->
<string name="permission_editing_not_allowed">Editing is not allowed</string> <string name="permission_editing_not_allowed">Editing is not allowed</string>
......
...@@ -32,20 +32,46 @@ suspend fun Bitmap.compressImageAndGetInputStream(mimeType: String): InputStream ...@@ -32,20 +32,46 @@ suspend fun Bitmap.compressImageAndGetInputStream(mimeType: String): InputStream
return inputStream return inputStream
} }
/**
* Returns a [ByteArray] of a [Bitmap].
*
* @param mimeType The MIME type of the [Bitmap].
* @param quality The quality of the [Bitmap] for the resulting [ByteArray].
* @param maxFileSizeAllowed The max file size allowed by the server. Note: The [quality] will be
* decreased minus 10 until the [ByteArray] size fits the [maxFileSizeAllowed] value.
* @return A [ByteArray] of a [Bitmap]
*/
suspend fun Bitmap.getByteArray(
mimeType: String,
quality: Int,
maxFileSizeAllowed: Int
): ByteArray {
lateinit var byteArray: ByteArray
compressImageAndGetByteArray(mimeType, quality)?.let {
if (it.size > maxFileSizeAllowed && maxFileSizeAllowed !in -1..0) {
getByteArray(mimeType, quality - 10, maxFileSizeAllowed)
} else {
byteArray = it
}
}
return byteArray
}
/** /**
* Compress a [Bitmap] image. * Compress a [Bitmap] image.
* *
* @param mimeType The MimeType of what the compressed image should be. * @param mimeType The MimeType of what the compressed image should be.
* @return An [ByteArray] of a compressed image, otherwise null if the compression couldn't be done. * @return An [ByteArray] of a compressed image, otherwise null if the compression couldn't be done.
*/ */
suspend fun Bitmap.compressImageAndGetByteArray(mimeType: String): ByteArray? { suspend fun Bitmap.compressImageAndGetByteArray(mimeType: String, quality: Int = 100): ByteArray? {
var byteArray: ByteArray? = null var byteArray: ByteArray? = null
withContext(DefaultDispatcher) { withContext(DefaultDispatcher) {
val byteArrayOutputStream = ByteArrayOutputStream() val byteArrayOutputStream = ByteArrayOutputStream()
// TODO: Add an option the the app to the user be able to select the quality of the compressed image
val isCompressed = val isCompressed =
this.compress(mimeType.getCompressFormat(), 70, byteArrayOutputStream) this.compress(mimeType.getCompressFormat(), quality, byteArrayOutputStream)
if (isCompressed) { if (isCompressed) {
byteArray = byteArrayOutputStream.toByteArray() byteArray = byteArrayOutputStream.toByteArray()
} }
......
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