diff --git a/app/src/main/java/org/thoughtcrime/securesms/SessionDialogBuilder.kt b/app/src/main/java/org/thoughtcrime/securesms/SessionDialogBuilder.kt
index 15b19956f9..cb97b3787f 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/SessionDialogBuilder.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/SessionDialogBuilder.kt
@@ -2,15 +2,21 @@ package org.thoughtcrime.securesms
import android.content.Context
import android.content.Intent
+import android.graphics.Typeface
import android.net.Uri
-import android.util.AttributeSet
+import android.text.Spannable
+import android.text.SpannableString
+import android.text.style.StyleSpan
+import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.widget.Button
+import android.widget.ImageButton
import android.widget.LinearLayout
import android.widget.LinearLayout.VERTICAL
+import android.widget.RelativeLayout
import android.widget.ScrollView
import android.widget.Space
import android.widget.TextView
@@ -22,7 +28,9 @@ import androidx.appcompat.app.AlertDialog
import androidx.core.text.HtmlCompat
import androidx.core.view.updateMargins
import androidx.fragment.app.Fragment
+import com.squareup.phrase.Phrase
import network.loki.messenger.R
+import org.session.libsession.utilities.StringSubstitutionConstants.URL_KEY
import org.thoughtcrime.securesms.conversation.v2.Util.writeTextToClipboard
import org.thoughtcrime.securesms.util.toPx
@@ -33,20 +41,22 @@ annotation class DialogDsl
@DialogDsl
class SessionDialogBuilder(val context: Context) {
- private val dp20 = toPx(20, context.resources)
- private val dp40 = toPx(40, context.resources)
- private val dp60 = toPx(60, context.resources)
+ val dp20 = toPx(20, context.resources)
+ val dp40 = toPx(40, context.resources)
+ val dp60 = toPx(60, context.resources)
private val dialogBuilder: AlertDialog.Builder = AlertDialog.Builder(context)
private var dialog: AlertDialog? = null
- private fun dismiss() = dialog?.dismiss()
+ fun dismiss() = dialog?.dismiss()
private val topView = LinearLayout(context)
.apply { setPadding(0, dp20, 0, 0) }
.apply { orientation = VERTICAL }
.also(dialogBuilder::setCustomTitle)
- private val contentView = LinearLayout(context).apply { orientation = VERTICAL }
+
+ val contentView = LinearLayout(context).apply { orientation = VERTICAL }
+
private val buttonLayout = LinearLayout(context)
private val root = LinearLayout(context).apply { orientation = VERTICAL }
@@ -56,39 +66,24 @@ class SessionDialogBuilder(val context: Context) {
addView(buttonLayout)
}
- fun title(@StringRes id: Int) = title(context.getString(id))
-
- fun title(text: CharSequence?) = title(text?.toString())
+ // Main title entry point
fun title(text: String?) {
text(text, R.style.TextAppearance_AppCompat_Title) { setPadding(dp20, 0, dp20, 0) }
}
+ // Convenience assessor for title that takes a string resource
+ fun title(@StringRes id: Int) = title(context.getString(id))
+
+ // Convenience accessor for title that takes a CharSequence
+ fun title(text: CharSequence?) = title(text?.toString())
+
fun text(@StringRes id: Int, style: Int = 0) = text(context.getString(id), style)
+
fun text(text: CharSequence?, @StyleRes style: Int = 0) {
text(text, style) {
layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT)
.apply { updateMargins(dp40, 0, dp40, 0) }
}
- }
-
- fun textWithMaxOfFiveLines(text: CharSequence?, @StyleRes style: Int = 0) {
-
- ScrollView(context, null, 0).apply {
- layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT)
-
- // fix this so it adds and shows a scrollbar if it exceeds 5 lines
- here!
- text(text, style) {
- maxLines = 5
- layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT)
- .apply { updateMargins(dp40, 0, dp40, 0) }
- }.apply { refreshDrawableState() }
-
- }
-
-
-
-
}
private fun text(text: CharSequence?, @StyleRes style: Int, modify: TextView.() -> Unit) {
@@ -148,11 +143,11 @@ class SessionDialogBuilder(val context: Context) {
) { listener() }
fun okButton(listener: (() -> Unit) = {}) = button(android.R.string.ok) { listener() }
+
fun cancelButton(listener: (() -> Unit) = {}) = button(android.R.string.cancel, R.string.AccessibilityId_cancel) { listener() }
fun copyUrlButton(listener: (() -> Unit) = {}) = button(android.R.string.copyUrl, R.string.AccessibilityId_copy) { listener() }
-
fun button(
@StringRes text: Int,
@StringRes contentDescriptionRes: Int = text,
@@ -176,32 +171,125 @@ class SessionDialogBuilder(val context: Context) {
fun Context.showSessionDialog(build: SessionDialogBuilder.() -> Unit): AlertDialog =
SessionDialogBuilder(this).apply { build() }.show()
-private fun Context.showOpenUrlDialogInner(build: SessionDialogBuilder.() -> Unit): AlertDialog =
- SessionDialogBuilder(this).apply {
- title(R.string.urlOpen)
- text(R.string.urlOpenBrowser)
- build()
- }.show()
-
-fun Context.showOpenUrlDialogPublicFacing(url: String): AlertDialog {
+// Method to show a dialog used to open or copy a URL
+fun Context.showOpenUrlDialog(url: String, showCloseButton: Boolean = true): AlertDialog {
return SessionDialogBuilder(this).apply {
- title(R.string.urlOpen)
- val txt = getString(R.string.urlOpenBrowser) + "\n\n" + "https://github.com/oxen-io/session-android/theworldslongrsturlisverylongindeedandshouldgoover5linesbecausethatswhatIneedtotestbecausemaryhadalittlelamb" //url
- textWithMaxOfFiveLines(txt)
- dangerButton(R.string.open) { openUrl(url) }
+ // If we're not showing a close button we can just use a simple title..
+ if (!showCloseButton) {
+ title(R.string.urlOpen)
+ } else {
+ // ..otherwise we have to jump through some hoops to add a close button.
+
+ // Create a RelativeLayout as the container for the custom title
+ val titleLayout = RelativeLayout(context).apply {
+ layoutParams = RelativeLayout.LayoutParams(
+ RelativeLayout.LayoutParams.MATCH_PARENT,
+ RelativeLayout.LayoutParams.WRAP_CONTENT
+ )
+ }
+
+ // Create a TextView for the title
+ val titleTextView = TextView(context).apply {
+ // Set the text and display it in the correct 'title' style
+ text = context.getString(R.string.urlOpen)
+ setTextAppearance(R.style.TextAppearance_AppCompat_Title)
+
+ layoutParams = RelativeLayout.LayoutParams(
+ RelativeLayout.LayoutParams.WRAP_CONTENT,
+ RelativeLayout.LayoutParams.WRAP_CONTENT
+ ).apply {
+ addRule(RelativeLayout.CENTER_HORIZONTAL)
+ addRule(RelativeLayout.CENTER_VERTICAL)
+ }
+ }
+
+ // Create an ImageButton for the close button
+ val closeButton = ImageButton(context).apply {
+ setImageResource(android.R.drawable.ic_menu_close_clear_cancel) // Use a standard Android close icon
+ background = null // Remove the background to make it look like an icon
+ layoutParams = RelativeLayout.LayoutParams(
+ RelativeLayout.LayoutParams.WRAP_CONTENT,
+ RelativeLayout.LayoutParams.WRAP_CONTENT
+ ).apply {
+ addRule(RelativeLayout.ALIGN_PARENT_END) // Place the close button on the "right" side
+ addRule(RelativeLayout.CENTER_VERTICAL)
+ }
+ contentDescription = context.getString(R.string.close)
+ }
+
+ // // Close the dialog when the button is clicked
+ closeButton.setOnClickListener { dismiss() }
+
+ // Add the TextView and ImageButton to the RelativeLayout..
+ titleLayout.addView(titleTextView)
+ titleLayout.addView(closeButton)
+
+ // ..and then add that layout to the contentView.
+ contentView.addView(titleLayout)
+ }
+
+ // Create a TextView for the "Are you sure you want to open this URL?"
+ val txtView = TextView(context).apply {
+ layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT)
+ .apply { updateMargins(dp40, 0, dp40, 0) }
+
+ // Substitute the URL into the string then make it bold
+ val txt = Phrase.from(context, R.string.urlOpenDescription).put(URL_KEY, url).format().toString()
+ val txtWithBoldedURL = SpannableString(txt)
+ val urlStart = txt.indexOf(url)
+ if (urlStart >= 0) {
+ txtWithBoldedURL.setSpan(
+ StyleSpan(Typeface.BOLD),
+ urlStart,
+ urlStart + url.length,
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
+ )
+ }
+ text = txtWithBoldedURL
+
+ gravity = Gravity.CENTER // Center the text
+ }
+
+ // Create a ScrollView and add the TextView to it
+ val scrollView = ScrollView(context).apply {
+ addView(txtView)
+
+ // Apply padding to the ScrollView so that the scroll bar isn't right up against the edge.
+ // We'll apply the same padding to both sides to keep the text centered.
+ setPadding(dp20, 0, dp20, 0)
+
+ // Place the scroll bar inside the container.
+ // See the following for how different options look: https://stackoverflow.com/questions/3103132/android-listview-scrollbarstyle
+ scrollBarStyle = ScrollView.SCROLLBARS_INSIDE_INSET
+ }
+
+ // If the textView takes up 5 lines or more then show the scroll bar, force it to remain visible,
+ // and set the ScrollView height accordingly.
+ txtView.viewTreeObserver.addOnGlobalLayoutListener {
+ // Only display the vertical scroll bar if the text takes up 5 lines or more
+ val maxLines = 5
+ if (txtView.lineCount >= maxLines) {
+ scrollView.isVerticalScrollBarEnabled = true
+ scrollView.setScrollbarFadingEnabled(false)
+ scrollView.isVerticalFadingEdgeEnabled = false
+ val lineHeight = txtView.lineHeight
+ scrollView.layoutParams.height = lineHeight * maxLines
+ }
+ }
+
+ // Add the ScrollView to the contentView and then add the 'Open' and 'Copy URL' buttons.
+ // Note: The text and contentDescription are set on the `copyUrlButton` by the function.
+ contentView.addView(scrollView)
+ dangerButton(R.string.open, R.string.AccessibilityId_urlOpenBrowser) { openUrl(url) }
copyUrlButton { writeTextToClipboard(context, url) }
}.show()
-
-
}
-// showOpenUrlDialogInner {
-// okButton { openUrl(url) }
-// cancelButton()
-// }
+// Method to actually open a given URL via an Intent that will use the default browser
fun Context.openUrl(url: String) = Intent(Intent.ACTION_VIEW, Uri.parse(url)).let(::startActivity)
fun Fragment.showSessionDialog(build: SessionDialogBuilder.() -> Unit): AlertDialog =
SessionDialogBuilder(requireContext()).apply { build() }.show()
+
fun Fragment.createSessionDialog(build: SessionDialogBuilder.() -> Unit): AlertDialog =
SessionDialogBuilder(requireContext()).apply { build() }.create()
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/LinkPreviewView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/LinkPreviewView.kt
index 3993b61a71..68da078e55 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/LinkPreviewView.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/LinkPreviewView.kt
@@ -8,20 +8,16 @@ import android.view.MotionEvent
import android.widget.LinearLayout
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
+import com.bumptech.glide.RequestManager
import network.loki.messenger.R
import network.loki.messenger.databinding.ViewLinkPreviewBinding
import org.session.libsession.utilities.getColorFromAttr
+import org.session.libsignal.utilities.Log
import org.thoughtcrime.securesms.components.CornerMask
-import org.thoughtcrime.securesms.conversation.v2.ModalUrlBottomSheet
import org.thoughtcrime.securesms.conversation.v2.utilities.MessageBubbleUtilities
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
-import com.bumptech.glide.RequestManager
-import org.session.libsignal.utilities.Log
-import org.thoughtcrime.securesms.SessionDialogBuilder
import org.thoughtcrime.securesms.mms.ImageSlide
-
-import org.thoughtcrime.securesms.showOpenUrlDialogPublicFacing
-
+import org.thoughtcrime.securesms.showOpenUrlDialog
class LinkPreviewView : LinearLayout {
private val binding: ViewLinkPreviewBinding by lazy { ViewLinkPreviewBinding.bind(this) }
@@ -89,17 +85,11 @@ class LinkPreviewView : LinearLayout {
}
}
- fun openURL() {
+ // Method to show the open or copy URL dialog
+ private fun openURL() {
val url = this.url ?: return Log.w("LinkPreviewView", "Cannot open a null URL")
val activity = context as AppCompatActivity
-
- // OLDE!
- //ModalUrlBottomSheet(url).show(activity.supportFragmentManager, "Open URL Dialog")
-
- activity.showOpenUrlDialogPublicFacing(url)
-
-
-
+ activity.showOpenUrlDialog(url)
}
// endregion
}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt
index 0f81aff376..1d193bd745 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt
@@ -40,6 +40,7 @@ import org.thoughtcrime.securesms.database.model.MmsMessageRecord
import org.thoughtcrime.securesms.database.model.SmsMessageRecord
import com.bumptech.glide.Glide
import com.bumptech.glide.RequestManager
+import org.thoughtcrime.securesms.showOpenUrlDialog
import org.thoughtcrime.securesms.util.GlowViewUtilities
import org.thoughtcrime.securesms.util.SearchUtil
import org.thoughtcrime.securesms.util.getAccentColor
@@ -293,7 +294,7 @@ class VisibleMessageContentView : ConstraintLayout {
val updatedUrl = urlSpan.url.let { it.toHttpUrlOrNull().toString() }
val replacementSpan = ModalURLSpan(updatedUrl) { url ->
val activity = context as AppCompatActivity
- ModalUrlBottomSheet(url).show(activity.supportFragmentManager, "Open URL Dialog")
+ activity.showOpenUrlDialog(url)
}
val start = body.getSpanStart(urlSpan)
val end = body.getSpanEnd(urlSpan)
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 60fd7087d2..b336d5ae02 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -122,11 +122,13 @@