diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index c439862ba..e0453e10c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -1338,12 +1338,21 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe override fun copyMessages(messages: Set) { val sortedMessages = messages.sortedBy { it.dateSent } + val messageSize = sortedMessages.size val builder = StringBuilder() - for (message in sortedMessages) { + val messageIterator = sortedMessages.iterator() + while (messageIterator.hasNext()) { + val message = messageIterator.next() val body = MentionUtilities.highlightMentions(message.body, threadID, this) if (TextUtils.isEmpty(body)) { continue } - val formattedTimestamp = DateUtils.getDisplayFormattedTimeSpanString(this, Locale.getDefault(), message.timestamp) - builder.append("$formattedTimestamp: $body").append('\n') + if (messageSize > 1) { + val formattedTimestamp = DateUtils.getDisplayFormattedTimeSpanString(this, Locale.getDefault(), message.timestamp) + builder.append("$formattedTimestamp: ") + } + builder.append(body) + if (messageIterator.hasNext()) { + builder.append('\n') + } } if (builder.isNotEmpty() && builder[builder.length - 1] == '\n') { builder.deleteCharAt(builder.length - 1) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ModalUrlBottomSheet.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ModalUrlBottomSheet.kt new file mode 100644 index 000000000..859f208a5 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ModalUrlBottomSheet.kt @@ -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() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/dialogs/OpenURLDialog.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/dialogs/OpenURLDialog.kt deleted file mode 100644 index ea0230f57..000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/dialogs/OpenURLDialog.kt +++ /dev/null @@ -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() - } -} \ No newline at end of file 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 0457f8270..45921122f 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 @@ -3,7 +3,6 @@ package org.thoughtcrime.securesms.conversation.v2.messages import android.content.Context import android.graphics.Canvas import android.graphics.Rect -import android.text.method.LinkMovementMethod import android.util.AttributeSet import android.view.LayoutInflater import android.view.MotionEvent @@ -11,20 +10,17 @@ import android.widget.LinearLayout import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import androidx.core.content.res.ResourcesCompat -import androidx.core.text.getSpans -import androidx.core.text.toSpannable 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.ModalUrlBottomSheet 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.database.model.MmsMessageRecord -import org.thoughtcrime.securesms.util.UiModeUtilities import org.thoughtcrime.securesms.mms.GlideRequests import org.thoughtcrime.securesms.mms.ImageSlide +import org.thoughtcrime.securesms.util.UiModeUtilities class LinkPreviewView : LinearLayout { private val cornerMask by lazy { CornerMask(this) } @@ -97,7 +93,7 @@ class LinkPreviewView : LinearLayout { fun openURL() { val url = this.url ?: return val activity = context as AppCompatActivity - OpenURLDialog(url).show(activity.supportFragmentManager, "Open URL Dialog") + ModalUrlBottomSheet(url).show(activity.supportFragmentManager, "Open URL Dialog") } // 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 38831ed5a..f98b3a23d 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 @@ -31,8 +31,8 @@ import org.session.libsession.utilities.ViewUtil import org.session.libsession.utilities.recipients.Recipient import org.thoughtcrime.securesms.components.emoji.EmojiTextView 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.dialogs.OpenURLDialog import org.thoughtcrime.securesms.conversation.v2.utilities.MentionUtilities import org.thoughtcrime.securesms.conversation.v2.utilities.ModalURLSpan 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 replacementSpan = ModalURLSpan(updatedUrl) { url -> 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 end = body.getSpanEnd(urlSpan) diff --git a/app/src/main/res/layout/fragment_modal_url_bottom_sheet.xml b/app/src/main/res/layout/fragment_modal_url_bottom_sheet.xml new file mode 100644 index 000000000..190d4ef0c --- /dev/null +++ b/app/src/main/res/layout/fragment_modal_url_bottom_sheet.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5dde92c69..e7c8afc1b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -872,6 +872,7 @@ Open URL? Are you sure you want to open %s? Open + Copy URL Enable Link Previews? Enabling link previews will show previews for URLs you send and receive. This can be useful, but Session will need to contact linked websites to generate previews. You can always disable link previews in Session\'s settings.