Skip to content

Commit

Permalink
Image rotation bug fix and refactor the message constructing in
Browse files Browse the repository at this point in the history
conversation view #161
  • Loading branch information
carmenlau committed Mar 16, 2018
2 parents c1620c9 + 2228809 commit 9a27839
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 122 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -389,16 +389,26 @@ open class ConversationFragment() :
/**
* This function is for receiving new message and sending new message.
*/
private fun addMessageToBottom(message: ChatMessage, uri: Uri? = null) {
val view = conversationView()
if (messageIDs.contains(message.id)) {
view?.updateMessages(listOf(message))
} else {
view?.addMessageToBottom(message, uri)
private fun upsertMessage(message: ChatMessage) {
conversationView()?.let { conversationView ->
val message = messageFromChatMessage(message, conversationView)
if (messageIDs.contains(message.id)) {
conversationView.updateMessages(listOf(message.chatMessage))
} else {
conversationView.addMessageToBottom(message)
messageIDs.add(message.id)
}
}
}

private fun addDeliveringMessage(message: Message) {
conversationView()?.let { conversationView ->
messageIDs.add(message.id)
conversationView.addMessageToBottom(message)
}
}

// mark last read message
private fun markMesseAsReadAndLastRead(message: ChatMessage) {
this.conversation?.let { conv ->
this.skygearChat?.markConversationLastReadMessage(conv, message)
}
Expand Down Expand Up @@ -524,7 +534,8 @@ open class ConversationFragment() :
}

private fun onReceiveChatMessage(msg: ChatMessage) {
this.addMessageToBottom(msg)
this.upsertMessage(msg)
this.markMesseAsReadAndLastRead(msg)
}

private fun onUpdateChatMessage(message: ChatMessage) {
Expand Down Expand Up @@ -642,7 +653,7 @@ open class ConversationFragment() :
stream.read(bytes, 0, bytes.size)
stream.close()

this.conversation?.let { conv ->
this.conversation?.let { conversation ->
val fileName = voiceRecordingFileName!!.split("/").last()
val asset = Asset(fileName, VoiceMessage.MIME_TYPE, bytes)

Expand All @@ -653,23 +664,31 @@ open class ConversationFragment() :
message.asset = asset
message.metadata = meta

this.fragmentMessageSentListener?.onBeforeMessageSent(this, message)
addMessageToBottom(message, Uri.parse("file://" + voiceRecordingFileName))
this.skygearChat?.addMessage(message, conv, object : SaveCallback<ChatMessage> {
override fun onSuccess(chatMsg: ChatMessage?) {
conversationView()?.let { conversationView ->
addDeliveringMessage(voiceMessageFromChatMessage(message, Uri.parse("file://" + voiceRecordingFileName), conversationView))
sendChatMessage(message, conversation, {
voiceRecordingFile.delete()
callMessageSentSuccessListener(message)
}
})
}
}
}

override fun onFail(error: Error) {
Log.e(
ConversationFragment.TAG,
"Failed to send voice message: ${error.message}"
)
this@ConversationFragment.fragmentMessageSentListener?.onMessageSentFailed(this@ConversationFragment, message, error)
}
})
private fun sendChatMessage(message: ChatMessage, conversation: ChatConversation, successCallBack: (ChatMessage?) -> (Any)) {
this.skygearChat?.addMessage(message, conversation, object : SaveCallback<ChatMessage> {
override fun onFail(error: Error) {
Log.e(
ConversationFragment.TAG,
"Failed to send voice message: ${error.message}"
)
this@ConversationFragment.fragmentMessageSentListener?.onMessageSentFailed(this@ConversationFragment, message, error)
}

override fun onSuccess(chatMsg: ChatMessage?) {
successCallBack(chatMsg)
}
}
)
}

fun callMessageSentSuccessListener(chatMsg: ChatMessage?) {
Expand All @@ -693,27 +712,19 @@ open class ConversationFragment() :
}
}

fun onSendMessage(input: String): Boolean {

this.conversation?.let { conv ->
val message = ChatMessage()
message.body = input
this.fragmentMessageSentListener?.onBeforeMessageSent(this, message)
this.addMessageToBottom(message)
this.skygearChat?.addMessage(message, conv, object : SaveCallback<ChatMessage> {
override fun onSuccess(msg: io.skygear.plugins.chat.Message?) {
private fun onSendMessage(input: String): Boolean {
this.conversation?.let { conversation ->
conversationView()?.let { conversationView ->
val message = ChatMessage()
message.body = input
this.fragmentMessageSentListener?.onBeforeMessageSent(this, message)
this.addDeliveringMessage(messageFromChatMessage(message, conversationView))
sendChatMessage(message, conversation, {
callMessageSentSuccessListener(message)
msg?.let { this@ConversationFragment.updateMessage(msg) }
}

override fun onFail(error: Error) {
this@ConversationFragment.fragmentMessageSentListener
?.onMessageSentFailed(this@ConversationFragment, message, error)
message?.let { this@ConversationFragment.updateMessage(message, error) }
}
})
this.updateMessage(message)
})
}
}

return true
}

Expand Down Expand Up @@ -783,7 +794,7 @@ open class ConversationFragment() :
})

this.deleteMessages(listOf(message))
this.addMessageToBottom(messageToResend)
this.upsertMessage(messageToResend)
}

fun cancelMessage(message: ChatMessage) {
Expand Down Expand Up @@ -833,30 +844,44 @@ open class ConversationFragment() :
})?.notifyRequestResult(permissions.toList(), grantResults.toList())
}

fun sendImageMessage(imageUri: Uri) {
val imageData = getResizedBitmap(context, imageUri)
private fun sendImageMessage(imageUri: Uri) {
val orientation = getImageOrientation(context, imageUri)
val imageData = getResizedBitmap(context, imageUri, orientation)
if (imageData == null) {
Log.w(TAG, "Failed to decode image from uri: %s".format(imageUri))
return
}

this.conversation?.let { conv ->
val imageMessage = MessageBuilder.createImageMessage(imageData)
this.fragmentMessageSentListener?.onBeforeMessageSent(this, imageMessage)
this.addMessageToBottom(imageMessage, imageUri)
this.skygearChat?.addMessage(imageMessage, conv, object : SaveCallback<io.skygear.plugins.chat.Message> {
override fun onSuccess(message: ChatMessage?) {
callMessageSentSuccessListener(message)
}

override fun onFail(error: Error) {
this@ConversationFragment.fragmentMessageSentListener
?.onMessageSentFailed(this@ConversationFragment, imageMessage, error)
}
})
this.conversation?.let { conversation ->
conversationView()?.let { conversationView ->
val imageMessage = MessageBuilder.createImageMessage(imageData)
this.fragmentMessageSentListener?.onBeforeMessageSent(this, imageMessage)
addDeliveringMessage(imageMessageFromChatMessage(imageMessage, imageUri, orientation, conversationView))
sendChatMessage(imageMessage, conversation, {
callMessageSentSuccessListener(imageMessage)
})
}
}
}

private fun imageMessageFromChatMessage(chatMessage: ChatMessage, uri: Uri, orientation: Int, conversationView: ConversationView): Message {
val message = MessageFactory.getMessage(chatMessage, conversationView.getMessageStyle(), uri, orientation)
conversationView.updateMessageAuthor(message)
return message
}

private fun voiceMessageFromChatMessage(chatMessage: ChatMessage, uri: Uri, conversationView: ConversationView): Message {
val message = MessageFactory.getMessage(chatMessage, conversationView.getMessageStyle(), uri)
conversationView.updateMessageAuthor(message)
return message
}

private fun messageFromChatMessage(chatMessage: ChatMessage, conversationView: ConversationView): Message {
val message = MessageFactory.getMessage(chatMessage, conversationView.getMessageStyle())
conversationView.updateMessageAuthor(message)
return message
}

private fun takePhotoFromCameraIntent() {
this.takePhotoPermissionManager?.runIfPermissionGranted {
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import com.dewarder.holdinglibrary.HoldingButtonLayout
import com.dewarder.holdinglibrary.HoldingButtonLayoutListener
import io.skygear.plugins.chat.ui.utils.ImageLoader
import android.app.Activity
import android.net.Uri
import android.os.Handler
import android.widget.* // ktlint-disable no-wildcard-imports
import io.skygear.plugins.chat.ui.holder.* // ktlint-disable no-wildcard-imports
Expand Down Expand Up @@ -378,13 +377,13 @@ open class ConversationView : RelativeLayout {
}

open fun updateMessages(chatMessages: List<ChatMessage>) {
for (message: Message in MessagesFromChatMessages(chatMessages)) {
for (message: Message in messagesFromChatMessages(chatMessages)) {
this.messageListAdapter?.update(message)
}
}

open fun updateMessages(chatMessages: List<ChatMessage>, error: Error) {
for (message: Message in MessagesFromChatMessages(chatMessages)) {
for (message: Message in messagesFromChatMessages(chatMessages)) {
message.error = error
this.messageListAdapter?.update(message)
}
Expand All @@ -396,19 +395,20 @@ open class ConversationView : RelativeLayout {
}

open fun mergeMessages(chatMessages: List<ChatMessage>) {
this.messageListAdapter?.merge(MessagesFromChatMessages(chatMessages))
this.messageListAdapter?.merge(messagesFromChatMessages(chatMessages))
}

open fun mergeMessages(chatMessages: List<ChatMessage>, error: Error) {
var messages = MessagesFromChatMessages(chatMessages)
var messages = messagesFromChatMessages(chatMessages)
for (message: Message in messages) {
message.error = error
}
this.messageListAdapter?.merge(messages)
}

open fun addMessageToBottom(message: ChatMessage, imageUri: Uri? = null) {
this.messageListAdapter?.addToStart(MessageFromChatMessage(message, imageUri), needToScrollToBottom())
open fun addMessageToBottom(message: Message) {
updateMessageAuthor(message)
this.messageListAdapter?.addToStart(message, needToScrollToBottom())
}

open fun startListeningScroll() {
Expand All @@ -435,33 +435,12 @@ open class ConversationView : RelativeLayout {
return MessageStyle(this.avatarHiddenForOutgoingMessages, this.avatarHiddenForIncomingMessages, this.messageSenderTextColor, getMessageStatusText(), dateFormat, timeStyle, bubbleStyle, voiceMessageStyle, statusStyle)
}

fun MessagesFromChatMessages(chatMessages: List<ChatMessage>): List<Message> {
val multitypeMessages = chatMessages.map {
private fun messagesFromChatMessages(chatMessages: List<ChatMessage>): List<Message> {
val multiTypeMessages = chatMessages.map {
MessageFactory.getMessage(it, getMessageStyle())
}
multitypeMessages.forEach { updateMessageAuthor(it) }
return multitypeMessages
}

fun MessagesFromChatMessages(chatMessages: List<ChatMessage>, error: Error): List<Message> {
val multitypeMessages = chatMessages.map {
MessageFactory.getMessage(it, getMessageStyle())
}
multitypeMessages.forEach {
updateMessageAuthor(it)
updateMessageError(it, error)
}
return multitypeMessages
}

fun MessageFromChatMessage(chatMessage: ChatMessage, uri: Uri?): Message {
val multitypeMessage = MessageFactory.getMessage(chatMessage, getMessageStyle(), uri)
updateMessageAuthor(multitypeMessage)
return multitypeMessage
}

fun updateMessageError(message: Message, error: Error) {
message.error = error
multiTypeMessages.forEach { updateMessageAuthor(it) }
return multiTypeMessages
}

fun updateMessageAuthor(message: Message) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@ package io.skygear.plugins.chat.ui

import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.net.Uri
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.Menu
import android.view.MenuItem
import android.widget.ImageView
import com.squareup.picasso.Picasso
import com.squareup.picasso.Transformation
import io.skygear.plugins.chat.ui.utils.getImageOrientation
import io.skygear.plugins.chat.ui.utils.matrixFromRotation

class ImagePreviewActivity : AppCompatActivity() {

Expand All @@ -25,15 +30,35 @@ class ImagePreviewActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_image_preview)

setTitle("")

val photoView = findViewById<ImageView>(R.id.iv_photo)
title = ""

var url = intent.getStringExtra(ImageURLIntentKey)

Picasso.with(this)
val fromContentResolver = url.startsWith("content")
if (fromContentResolver) {
url = url.substring(0, url.indexOf("?"))
}
val creator = Picasso.with(this)
.load(url)
.into(photoView)

if (fromContentResolver) {
val orientation = getImageOrientation(this, Uri.parse(url))
var matrix = matrixFromRotation(orientation)

matrix?.let {
creator.transform(object : Transformation {
override fun key(): String {
return "orientation"
}

override fun transform(source: Bitmap?): Bitmap {
val bmRotated = Bitmap.createBitmap(source, 0, 0, source!!.width, source!!.height, matrix, true)
source?.recycle()
return bmRotated
}
})
}
}
creator.into(findViewById<ImageView>(R.id.iv_photo))
}

override fun onCreateOptionsMenu(menu: Menu): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ class ImageMessage : Message,

val chatMessageImageUrl: String?

constructor(m: ChatMessage, imageUri: Uri?, style: MessageStyle) : super(m, style) {
constructor(m: ChatMessage, imageUri: Uri?, orientation: Int?, style: MessageStyle) : super(m, style) {
this.chatMessageImageUrl = this.imageUrlFromChatMessage(
this.chatMessage.asset?.url ?: imageUri?.toString(),
this.chatMessage.metadata)
this.chatMessage.metadata, orientation)
}

override fun getImageUrl(): String? = this.chatMessageImageUrl

fun imageUrlFromChatMessage(imageUrl: String?, meta: JSONObject?): String? {
fun imageUrlFromChatMessage(imageUrl: String?, meta: JSONObject?, orientation: Int?): String? {
var url = imageUrl
if (url == null) {
return null
Expand All @@ -43,6 +43,10 @@ class ImageMessage : Message,
builder.appendQueryParameter("height", it.getInt("height").toString())
}

orientation?.let {
builder.appendQueryParameter("orientation", orientation.toString())
}

url = builder.build().toString()
}
return url
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import android.net.Uri

class MessageFactory {
companion object {
fun getMessage(m: ChatMessage, style: MessageStyle, uri: Uri? = null): Message {
fun getMessage(m: ChatMessage, style: MessageStyle, uri: Uri? = null, orientation: Int? = null): Message {
return m.asset?.mimeType.let {
when {
it?.startsWith("image") == true -> ImageMessage(m, uri, style)
it?.startsWith("image") == true -> ImageMessage(m, uri, orientation, style)
it?.equals(VoiceMessage.MIME_TYPE) == true -> VoiceMessage(m, style, uri)
else -> Message(m, style)
}
Expand Down
Loading

0 comments on commit 9a27839

Please sign in to comment.