mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-27 12:05:22 +00:00
Merge branch 'ui' of https://github.com/oxen-io/session-android into ui
This commit is contained in:
commit
19d683082e
@ -613,6 +613,9 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
|
||||
// region Interaction
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
if (item.itemId == android.R.id.home) {
|
||||
return false
|
||||
}
|
||||
return ConversationMenuHelper.onOptionItemSelected(this, item, thread)
|
||||
}
|
||||
|
||||
|
@ -1,23 +1,20 @@
|
||||
package org.thoughtcrime.securesms.conversation.v2.messages
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.net.Uri
|
||||
import android.graphics.Rect
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewOutlineProvider
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.core.view.isVisible
|
||||
import kotlinx.android.synthetic.main.view_link_preview.view.*
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.components.CornerMask
|
||||
import org.thoughtcrime.securesms.conversation.v2.dialogs.OpenURLDialog
|
||||
import org.thoughtcrime.securesms.conversation.v2.utilities.MessageBubbleUtilities
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord
|
||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
||||
import org.thoughtcrime.securesms.loki.utilities.UiModeUtilities
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests
|
||||
@ -44,7 +41,8 @@ class LinkPreviewView : LinearLayout {
|
||||
// Thumbnail
|
||||
if (linkPreview.getThumbnail().isPresent) {
|
||||
// This internally fetches the thumbnail
|
||||
thumbnailImageView.setImageResource(glide, ImageSlide(context, linkPreview.getThumbnail().get()), false, false)
|
||||
thumbnailImageView.setImageResource(glide, ImageSlide(context, linkPreview.getThumbnail().get()), isPreview = false)
|
||||
thumbnailImageView.loadIndicator.isVisible = false
|
||||
}
|
||||
// Title
|
||||
titleTextView.text = linkPreview.title
|
||||
@ -72,6 +70,14 @@ class LinkPreviewView : LinearLayout {
|
||||
// endregion
|
||||
|
||||
// region Interaction
|
||||
fun calculateHit(hitRect: Rect) {
|
||||
val previewRect = Rect()
|
||||
mainLinkPreviewParent.getGlobalVisibleRect(previewRect)
|
||||
if (previewRect.contains(hitRect)) {
|
||||
openURL()
|
||||
}
|
||||
}
|
||||
|
||||
fun openURL() {
|
||||
val url = this.url ?: return
|
||||
val activity = context as AppCompatActivity
|
||||
|
@ -6,18 +6,21 @@ import android.graphics.Rect
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.text.style.BackgroundColorSpan
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.text.style.URLSpan
|
||||
import android.text.util.Linkify
|
||||
import android.util.AttributeSet
|
||||
import android.util.TypedValue
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.core.graphics.BlendModeColorFilterCompat
|
||||
import androidx.core.graphics.BlendModeCompat
|
||||
import androidx.core.text.getSpans
|
||||
import androidx.core.text.toSpannable
|
||||
import kotlinx.android.synthetic.main.view_visible_message_content.view.*
|
||||
import network.loki.messenger.R
|
||||
@ -26,6 +29,8 @@ import org.session.libsession.utilities.ViewUtil
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.conversation.v2.components.AlbumThumbnailView
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||
import org.thoughtcrime.securesms.conversation.v2.dialogs.OpenURLDialog
|
||||
import org.thoughtcrime.securesms.conversation.v2.utilities.ModalURLSpan
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord
|
||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
||||
import org.thoughtcrime.securesms.loki.utilities.*
|
||||
@ -67,7 +72,9 @@ class VisibleMessageContentView : LinearLayout {
|
||||
val linkPreviewView = LinkPreviewView(context)
|
||||
linkPreviewView.bind(message, glide, isStartOfMessageCluster, isEndOfMessageCluster, searchQuery)
|
||||
mainContainer.addView(linkPreviewView)
|
||||
onContentClick = { linkPreviewView.openURL() }
|
||||
onContentClick = { rect ->
|
||||
linkPreviewView.calculateHit(rect)
|
||||
}
|
||||
// Body text view is inside the link preview for layout convenience
|
||||
} else if (message is MmsMessageRecord && message.quote != null) {
|
||||
val quote = message.quote!!
|
||||
@ -92,7 +99,7 @@ class VisibleMessageContentView : LinearLayout {
|
||||
onContentDoubleTap = { voiceMessageView.handleDoubleTap() }
|
||||
} else if (message is MmsMessageRecord && message.slideDeck.documentSlide != null) {
|
||||
val documentView = DocumentView(context)
|
||||
documentView.bind(message, VisibleMessageContentView.getTextColor(context, message))
|
||||
documentView.bind(message, getTextColor(context, message))
|
||||
mainContainer.addView(documentView)
|
||||
} else if (message is MmsMessageRecord && message.slideDeck.asAttachments().isNotEmpty()) {
|
||||
val albumThumbnailView = AlbumThumbnailView(context)
|
||||
@ -108,13 +115,12 @@ class VisibleMessageContentView : LinearLayout {
|
||||
onContentClick = { albumThumbnailView.calculateHitObject(it, message) }
|
||||
} else if (message.isOpenGroupInvitation) {
|
||||
val openGroupInvitationView = OpenGroupInvitationView(context)
|
||||
openGroupInvitationView.bind(message, VisibleMessageContentView.getTextColor(context, message))
|
||||
openGroupInvitationView.bind(message, getTextColor(context, message))
|
||||
mainContainer.addView(openGroupInvitationView)
|
||||
onContentClick = { openGroupInvitationView.joinOpenGroup() }
|
||||
} else {
|
||||
val bodyTextView = VisibleMessageContentView.getBodyTextView(context, message, searchQuery)
|
||||
val bodyTextView = getBodyTextView(context, message, searchQuery)
|
||||
mainContainer.addView(bodyTextView)
|
||||
onContentClick = { openURLIfNeeded(message) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,12 +144,6 @@ class VisibleMessageContentView : LinearLayout {
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region Interaction
|
||||
private fun openURLIfNeeded(message: MessageRecord) {
|
||||
Toast.makeText(context, "Not yet implemented", Toast.LENGTH_LONG).show()
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region Convenience
|
||||
companion object {
|
||||
|
||||
@ -158,10 +158,25 @@ class VisibleMessageContentView : LinearLayout {
|
||||
result.setLinkTextColor(color)
|
||||
var body = message.body.toSpannable()
|
||||
Linkify.addLinks(body, Linkify.WEB_URLS)
|
||||
|
||||
// replace URLSpans with ModalURLSpans
|
||||
body.getSpans<URLSpan>(0, body.length).toList().forEach { urlSpan ->
|
||||
val replacementSpan = ModalURLSpan(urlSpan.url) { url ->
|
||||
val activity = context as AppCompatActivity
|
||||
OpenURLDialog(url).show(activity.supportFragmentManager, "Open URL Dialog")
|
||||
}
|
||||
val start = body.getSpanStart(urlSpan)
|
||||
val end = body.getSpanEnd(urlSpan)
|
||||
val flags = body.getSpanFlags(urlSpan)
|
||||
body.removeSpan(urlSpan)
|
||||
body.setSpan(replacementSpan, start, end, flags)
|
||||
}
|
||||
|
||||
body = MentionUtilities.highlightMentions(body, message.isOutgoing, message.threadId, context);
|
||||
body = SearchUtil.getHighlightedSpan(Locale.getDefault(), StyleFactory { BackgroundColorSpan(Color.WHITE) }, body, searchQuery)
|
||||
body = SearchUtil.getHighlightedSpan(Locale.getDefault(), StyleFactory { ForegroundColorSpan(Color.BLACK) }, body, searchQuery)
|
||||
result.text = body
|
||||
result.movementMethod = LinkMovementMethod.getInstance()
|
||||
return result
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ import org.thoughtcrime.securesms.components.GlideBitmapListeningTarget
|
||||
import org.thoughtcrime.securesms.components.GlideDrawableListeningTarget
|
||||
import org.thoughtcrime.securesms.mms.*
|
||||
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri
|
||||
import org.thoughtcrime.securesms.util.MediaUtil
|
||||
|
||||
open class KThumbnailView: FrameLayout {
|
||||
|
||||
@ -38,7 +39,6 @@ open class KThumbnailView: FrameLayout {
|
||||
|
||||
private val image by lazy { thumbnail_image }
|
||||
private val playOverlay by lazy { play_overlay }
|
||||
private val captionIcon by lazy { thumbnail_caption_icon }
|
||||
val loadIndicator: View by lazy { thumbnail_load_indicator }
|
||||
|
||||
private val dimensDelegate = ThumbnailDimensDelegate()
|
||||
@ -110,7 +110,6 @@ open class KThumbnailView: FrameLayout {
|
||||
|
||||
this.slide = slide
|
||||
|
||||
captionIcon.isVisible = slide.caption.isPresent
|
||||
loadIndicator.isVisible = slide.isInProgress
|
||||
|
||||
dimensDelegate.setDimens(naturalWidth, naturalHeight)
|
||||
|
@ -0,0 +1,10 @@
|
||||
package org.thoughtcrime.securesms.conversation.v2.utilities
|
||||
|
||||
import android.text.style.URLSpan
|
||||
import android.view.View
|
||||
|
||||
class ModalURLSpan(url: String, private val openModalCallback: (String)->Unit): URLSpan(url) {
|
||||
override fun onClick(widget: View) {
|
||||
openModalCallback(url)
|
||||
}
|
||||
}
|
@ -57,7 +57,6 @@ public class ThumbnailView extends FrameLayout {
|
||||
|
||||
private ImageView image;
|
||||
private View playOverlay;
|
||||
private View captionIcon;
|
||||
private View loadIndicator;
|
||||
private OnClickListener parentClickListener;
|
||||
|
||||
@ -87,7 +86,6 @@ public class ThumbnailView extends FrameLayout {
|
||||
|
||||
this.image = findViewById(R.id.thumbnail_image);
|
||||
this.playOverlay = findViewById(R.id.play_overlay);
|
||||
this.captionIcon = findViewById(R.id.thumbnail_caption_icon);
|
||||
this.loadIndicator = findViewById(R.id.thumbnail_load_indicator);
|
||||
super.setOnClickListener(new ThumbnailClickDispatcher());
|
||||
|
||||
@ -278,8 +276,6 @@ public class ThumbnailView extends FrameLayout {
|
||||
|
||||
this.slide = slide;
|
||||
|
||||
this.captionIcon.setVisibility(GONE);
|
||||
|
||||
dimens[WIDTH] = naturalWidth;
|
||||
dimens[HEIGHT] = naturalHeight;
|
||||
invalidate();
|
||||
|
@ -14,14 +14,6 @@
|
||||
android:scaleType="fitCenter"
|
||||
android:contentDescription="@string/conversation_item__mms_image_description" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/thumbnail_caption_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="6dp"
|
||||
android:src="@drawable/ic_caption_28"
|
||||
android:visibility="gone" />
|
||||
|
||||
<org.thoughtcrime.securesms.conversation.v2.utilities.ThumbnailProgressBar
|
||||
android:id="@+id/thumbnail_load_indicator"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -8,6 +8,7 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/mainLinkPreviewParent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
@ -24,7 +25,7 @@
|
||||
android:src="@drawable/ic_link"
|
||||
app:tint="@color/text" />
|
||||
|
||||
<org.thoughtcrime.securesms.conversation.v2.utilities.ThumbnailView
|
||||
<org.thoughtcrime.securesms.conversation.v2.utilities.KThumbnailView
|
||||
android:id="@+id/thumbnailImageView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
@ -7,6 +7,7 @@ import nl.komponents.kovenant.functional.map
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.Request
|
||||
import okhttp3.RequestBody
|
||||
import org.session.libsession.messaging.jobs.Job.Companion.MAX_BUFFER_SIZE
|
||||
|
||||
import org.session.libsession.messaging.sending_receiving.notifications.PushNotificationAPI
|
||||
import org.session.libsession.messaging.utilities.Data
|
||||
@ -64,7 +65,7 @@ class NotifyPNServerJob(val message: SnodeMessage) : Job {
|
||||
val kryo = Kryo()
|
||||
kryo.isRegistrationRequired = false
|
||||
val serializedMessage = ByteArray(4096)
|
||||
val output = Output(serializedMessage)
|
||||
val output = Output(serializedMessage, MAX_BUFFER_SIZE)
|
||||
kryo.writeObject(output, message)
|
||||
output.close()
|
||||
return Data.Builder()
|
||||
|
@ -433,11 +433,12 @@ object OnionRequestAPI {
|
||||
internal fun sendOnionRequest(method: Snode.Method, parameters: Map<*, *>, snode: Snode, publicKey: String? = null): Promise<Map<*, *>, Exception> {
|
||||
val payload = mapOf( "method" to method.rawValue, "params" to parameters )
|
||||
return sendOnionRequest(Destination.Snode(snode), payload).recover { exception ->
|
||||
val httpRequestFailedException = exception as? HTTP.HTTPRequestFailedException
|
||||
if (httpRequestFailedException != null) {
|
||||
val error = SnodeAPI.handleSnodeError(httpRequestFailedException.statusCode, httpRequestFailedException.json, snode, publicKey)
|
||||
if (error != null) { throw error }
|
||||
val error = when (exception) {
|
||||
is HTTP.HTTPRequestFailedException -> SnodeAPI.handleSnodeError(exception.statusCode, exception.json, snode, publicKey)
|
||||
is HTTPRequestFailedAtDestinationException -> SnodeAPI.handleSnodeError(exception.statusCode, exception.json, snode, publicKey)
|
||||
else -> null
|
||||
}
|
||||
if (error != null) { throw error }
|
||||
throw exception
|
||||
}
|
||||
}
|
||||
|
@ -290,9 +290,7 @@ object SnodeAPI {
|
||||
getTargetSnodes(destination).map { swarm ->
|
||||
swarm.map { snode ->
|
||||
val parameters = message.toJSON()
|
||||
retryIfNeeded(maxRetryCount) {
|
||||
invoke(Snode.Method.SendMessage, snode, destination, parameters)
|
||||
}
|
||||
invoke(Snode.Method.SendMessage, snode, destination, parameters)
|
||||
}.toSet()
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user