mirror of
https://github.com/oxen-io/session-android.git
synced 2025-04-21 22:31:30 +00:00
feat: add bottom sheet modal url with copy option
This commit is contained in:
parent
ef3d2bb28f
commit
66e95787a2
@ -0,0 +1,72 @@
|
|||||||
|
package org.thoughtcrime.securesms.conversation.v2
|
||||||
|
|
||||||
|
import android.content.ClipData
|
||||||
|
import android.content.ClipboardManager
|
||||||
|
import android.content.Context.CLIPBOARD_SERVICE
|
||||||
|
import android.content.Intent
|
||||||
|
import android.graphics.Typeface
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.text.Spannable
|
||||||
|
import android.text.SpannableStringBuilder
|
||||||
|
import android.text.style.StyleSpan
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.Toast
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
|
import kotlinx.android.synthetic.main.fragment_modal_url_bottom_sheet.*
|
||||||
|
import network.loki.messenger.R
|
||||||
|
import org.thoughtcrime.securesms.util.UiModeUtilities
|
||||||
|
|
||||||
|
class ModalUrlBottomSheet(private val url: String): BottomSheetDialogFragment(), View.OnClickListener {
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View? {
|
||||||
|
return inflater.inflate(R.layout.fragment_modal_url_bottom_sheet, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
val explanation = resources.getString(R.string.dialog_open_url_explanation, url)
|
||||||
|
val spannable = SpannableStringBuilder(explanation)
|
||||||
|
val startIndex = explanation.indexOf(url)
|
||||||
|
spannable.setSpan(StyleSpan(Typeface.BOLD), startIndex, startIndex + url.count(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
|
openURLExplanationTextView.text = spannable
|
||||||
|
cancelButton.setOnClickListener(this)
|
||||||
|
copyButton.setOnClickListener(this)
|
||||||
|
openURLButton.setOnClickListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun open() {
|
||||||
|
try {
|
||||||
|
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
||||||
|
requireContext().startActivity(intent)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Toast.makeText(context, R.string.invalid_url, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun copy() {
|
||||||
|
val clip = ClipData.newPlainText("URL", url)
|
||||||
|
val manager = requireContext().getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
|
||||||
|
manager.setPrimaryClip(clip)
|
||||||
|
Toast.makeText(requireContext(), R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show()
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
val window = dialog?.window ?: return
|
||||||
|
val isLightMode = UiModeUtilities.isDayUiMode(requireContext())
|
||||||
|
window.setDimAmount(if (isLightMode) 0.1f else 0.75f)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onClick(v: View?) {
|
||||||
|
when (v) {
|
||||||
|
openURLButton -> open()
|
||||||
|
copyButton -> copy()
|
||||||
|
cancelButton -> dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,40 +0,0 @@
|
|||||||
package org.thoughtcrime.securesms.conversation.v2.dialogs
|
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import android.graphics.Typeface
|
|
||||||
import android.net.Uri
|
|
||||||
import android.text.Spannable
|
|
||||||
import android.text.SpannableStringBuilder
|
|
||||||
import android.text.style.StyleSpan
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.widget.Toast
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
|
||||||
import kotlinx.android.synthetic.main.dialog_open_url.view.*
|
|
||||||
import network.loki.messenger.R
|
|
||||||
import org.thoughtcrime.securesms.conversation.v2.utilities.BaseDialog
|
|
||||||
|
|
||||||
/** Shown upon tapping a URL. */
|
|
||||||
class OpenURLDialog(private val url: String) : BaseDialog() {
|
|
||||||
|
|
||||||
override fun setContentView(builder: AlertDialog.Builder) {
|
|
||||||
val contentView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_open_url, null)
|
|
||||||
val explanation = resources.getString(R.string.dialog_open_url_explanation, url)
|
|
||||||
val spannable = SpannableStringBuilder(explanation)
|
|
||||||
val startIndex = explanation.indexOf(url)
|
|
||||||
spannable.setSpan(StyleSpan(Typeface.BOLD), startIndex, startIndex + url.count(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
|
||||||
contentView.openURLExplanationTextView.text = spannable
|
|
||||||
contentView.cancelButton.setOnClickListener { dismiss() }
|
|
||||||
contentView.openURLButton.setOnClickListener { open() }
|
|
||||||
builder.setView(contentView)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun open() {
|
|
||||||
try {
|
|
||||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
|
||||||
requireContext().startActivity(intent)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Toast.makeText(context, R.string.invalid_url, Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
dismiss()
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,7 +3,6 @@ package org.thoughtcrime.securesms.conversation.v2.messages
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
import android.text.method.LinkMovementMethod
|
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
@ -11,20 +10,17 @@ import android.widget.LinearLayout
|
|||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
import androidx.core.text.getSpans
|
|
||||||
import androidx.core.text.toSpannable
|
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import kotlinx.android.synthetic.main.view_link_preview.view.*
|
import kotlinx.android.synthetic.main.view_link_preview.view.*
|
||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
import org.thoughtcrime.securesms.components.CornerMask
|
import org.thoughtcrime.securesms.components.CornerMask
|
||||||
import org.thoughtcrime.securesms.conversation.v2.dialogs.OpenURLDialog
|
import org.thoughtcrime.securesms.conversation.v2.ModalUrlBottomSheet
|
||||||
import org.thoughtcrime.securesms.conversation.v2.utilities.MessageBubbleUtilities
|
import org.thoughtcrime.securesms.conversation.v2.utilities.MessageBubbleUtilities
|
||||||
import org.thoughtcrime.securesms.conversation.v2.utilities.ModalURLSpan
|
|
||||||
import org.thoughtcrime.securesms.conversation.v2.utilities.TextUtilities.getIntersectedModalSpans
|
import org.thoughtcrime.securesms.conversation.v2.utilities.TextUtilities.getIntersectedModalSpans
|
||||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
||||||
import org.thoughtcrime.securesms.util.UiModeUtilities
|
|
||||||
import org.thoughtcrime.securesms.mms.GlideRequests
|
import org.thoughtcrime.securesms.mms.GlideRequests
|
||||||
import org.thoughtcrime.securesms.mms.ImageSlide
|
import org.thoughtcrime.securesms.mms.ImageSlide
|
||||||
|
import org.thoughtcrime.securesms.util.UiModeUtilities
|
||||||
|
|
||||||
class LinkPreviewView : LinearLayout {
|
class LinkPreviewView : LinearLayout {
|
||||||
private val cornerMask by lazy { CornerMask(this) }
|
private val cornerMask by lazy { CornerMask(this) }
|
||||||
@ -97,7 +93,7 @@ class LinkPreviewView : LinearLayout {
|
|||||||
fun openURL() {
|
fun openURL() {
|
||||||
val url = this.url ?: return
|
val url = this.url ?: return
|
||||||
val activity = context as AppCompatActivity
|
val activity = context as AppCompatActivity
|
||||||
OpenURLDialog(url).show(activity.supportFragmentManager, "Open URL Dialog")
|
ModalUrlBottomSheet(url).show(activity.supportFragmentManager, "Open URL Dialog")
|
||||||
}
|
}
|
||||||
// endregion
|
// endregion
|
||||||
}
|
}
|
@ -31,8 +31,8 @@ import org.session.libsession.utilities.ViewUtil
|
|||||||
import org.session.libsession.utilities.recipients.Recipient
|
import org.session.libsession.utilities.recipients.Recipient
|
||||||
import org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
import org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||||
import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2
|
import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2
|
||||||
|
import org.thoughtcrime.securesms.conversation.v2.ModalUrlBottomSheet
|
||||||
import org.thoughtcrime.securesms.conversation.v2.components.AlbumThumbnailView
|
import org.thoughtcrime.securesms.conversation.v2.components.AlbumThumbnailView
|
||||||
import org.thoughtcrime.securesms.conversation.v2.dialogs.OpenURLDialog
|
|
||||||
import org.thoughtcrime.securesms.conversation.v2.utilities.MentionUtilities
|
import org.thoughtcrime.securesms.conversation.v2.utilities.MentionUtilities
|
||||||
import org.thoughtcrime.securesms.conversation.v2.utilities.ModalURLSpan
|
import org.thoughtcrime.securesms.conversation.v2.utilities.ModalURLSpan
|
||||||
import org.thoughtcrime.securesms.conversation.v2.utilities.TextUtilities.getIntersectedModalSpans
|
import org.thoughtcrime.securesms.conversation.v2.utilities.TextUtilities.getIntersectedModalSpans
|
||||||
@ -237,7 +237,7 @@ class VisibleMessageContentView : LinearLayout {
|
|||||||
val updatedUrl = urlSpan.url.let { HttpUrl.parse(it).toString() }
|
val updatedUrl = urlSpan.url.let { HttpUrl.parse(it).toString() }
|
||||||
val replacementSpan = ModalURLSpan(updatedUrl) { url ->
|
val replacementSpan = ModalURLSpan(updatedUrl) { url ->
|
||||||
val activity = context as AppCompatActivity
|
val activity = context as AppCompatActivity
|
||||||
OpenURLDialog(url).show(activity.supportFragmentManager, "Open URL Dialog")
|
ModalUrlBottomSheet(url).show(activity.supportFragmentManager, "Open URL Dialog")
|
||||||
}
|
}
|
||||||
val start = body.getSpanStart(urlSpan)
|
val start = body.getSpanStart(urlSpan)
|
||||||
val end = body.getSpanEnd(urlSpan)
|
val end = body.getSpanEnd(urlSpan)
|
||||||
|
58
app/src/main/res/layout/fragment_modal_url_bottom_sheet.xml
Normal file
58
app/src/main/res/layout/fragment_modal_url_bottom_sheet.xml
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:behavior_hideable="true"
|
||||||
|
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:paddingVertical="@dimen/large_spacing"
|
||||||
|
>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/openURLTitleTextView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/dialog_open_url_title"
|
||||||
|
android:textColor="@color/text"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textSize="@dimen/large_font_size" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/openURLExplanationTextView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/dialog_open_url_explanation"
|
||||||
|
android:paddingHorizontal="@dimen/medium_spacing"
|
||||||
|
android:textColor="@color/text"
|
||||||
|
android:textSize="@dimen/small_font_size"
|
||||||
|
android:layout_margin="@dimen/large_spacing"
|
||||||
|
android:textAlignment="center" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/openURLButton"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/BottomSheetActionItem"
|
||||||
|
android:text="@string/open"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/copyButton"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/BottomSheetActionItem"
|
||||||
|
android:text="@string/copy"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:textColor="@color/destructive"
|
||||||
|
android:id="@+id/cancelButton"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/BottomSheetActionItem"
|
||||||
|
android:text="@string/cancel"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
Loading…
x
Reference in New Issue
Block a user