mirror of
https://github.com/oxen-io/session-android.git
synced 2025-02-17 13:08:25 +00:00
Merge branch 'dev'
This commit is contained in:
commit
c67d164db6
@ -153,8 +153,8 @@ dependencies {
|
||||
testImplementation 'org.robolectric:shadows-multidex:4.4'
|
||||
}
|
||||
|
||||
def canonicalVersionCode = 221
|
||||
def canonicalVersionName = "1.11.9"
|
||||
def canonicalVersionCode = 222
|
||||
def canonicalVersionName = "1.11.10"
|
||||
|
||||
def postFixSize = 10
|
||||
def abiPostFix = ['armeabi-v7a' : 1,
|
||||
|
@ -3,10 +3,7 @@ package org.thoughtcrime.securesms.conversation.v2
|
||||
import android.Manifest
|
||||
import android.animation.FloatEvaluator
|
||||
import android.animation.ValueAnimator
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.*
|
||||
import android.content.res.Resources
|
||||
import android.database.Cursor
|
||||
import android.graphics.Rect
|
||||
@ -237,7 +234,14 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
setUpLinkPreviewObserver()
|
||||
restoreDraftIfNeeded()
|
||||
addOpenGroupGuidelinesIfNeeded()
|
||||
scrollToBottomButton.setOnClickListener { conversationRecyclerView.smoothScrollToPosition(0) }
|
||||
scrollToBottomButton.setOnClickListener {
|
||||
val layoutManager = conversationRecyclerView.layoutManager ?: return@setOnClickListener
|
||||
if (layoutManager.isSmoothScrolling) {
|
||||
conversationRecyclerView.scrollToPosition(0)
|
||||
} else {
|
||||
conversationRecyclerView.smoothScrollToPosition(0)
|
||||
}
|
||||
}
|
||||
unreadCount = DatabaseFactory.getMmsSmsDatabase(this).getUnreadCount(threadID)
|
||||
updateUnreadCountIndicator()
|
||||
setUpTypingObserver()
|
||||
@ -972,7 +976,23 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
}
|
||||
|
||||
private fun showGIFPicker() {
|
||||
AttachmentManager.selectGif(this, ConversationActivityV2.PICK_GIF)
|
||||
val hasSeenGIFMetaDataWarning: Boolean = TextSecurePreferences.hasSeenGIFMetaDataWarning(this)
|
||||
if (!hasSeenGIFMetaDataWarning) {
|
||||
val builder = AlertDialog.Builder(this)
|
||||
builder.setTitle("Search GIFs?")
|
||||
builder.setMessage("You will not have full metadata protection when sending GIFs.")
|
||||
builder.setPositiveButton("OK") { dialog: DialogInterface, which: Int ->
|
||||
TextSecurePreferences.setHasSeenGIFMetaDataWarning(this)
|
||||
AttachmentManager.selectGif(this, ConversationActivityV2.PICK_GIF)
|
||||
dialog.dismiss()
|
||||
}
|
||||
builder.setNegativeButton(
|
||||
"Cancel"
|
||||
) { dialog: DialogInterface, which: Int -> dialog.dismiss() }
|
||||
builder.create().show()
|
||||
} else {
|
||||
AttachmentManager.selectGif(this, ConversationActivityV2.PICK_GIF)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showDocumentPicker() {
|
||||
@ -1325,12 +1345,21 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
|
||||
override fun copyMessages(messages: Set<MessageRecord>) {
|
||||
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)
|
||||
|
@ -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,16 +1,18 @@
|
||||
package org.thoughtcrime.securesms.conversation.v2.components;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import network.loki.messenger.R;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.session.libsession.utilities.Util;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import network.loki.messenger.R;
|
||||
|
||||
public class ExpirationTimerView extends androidx.appcompat.widget.AppCompatImageView {
|
||||
|
||||
private long startedAt;
|
||||
@ -86,10 +88,12 @@ public class ExpirationTimerView extends androidx.appcompat.widget.AppCompatImag
|
||||
long progressed = System.currentTimeMillis() - startedAt;
|
||||
long remaining = expiresIn - progressed;
|
||||
|
||||
if (remaining < TimeUnit.SECONDS.toMillis(30)) {
|
||||
return 50;
|
||||
} else {
|
||||
if (remaining <= 0) {
|
||||
return 0;
|
||||
} else if (remaining < TimeUnit.SECONDS.toMillis(30)) {
|
||||
return 1000;
|
||||
} else {
|
||||
return 5000;
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,16 +110,20 @@ public class ExpirationTimerView extends androidx.appcompat.widget.AppCompatImag
|
||||
ExpirationTimerView timerView = expirationTimerViewReference.get();
|
||||
if (timerView == null) return;
|
||||
|
||||
timerView.setExpirationTime(timerView.startedAt, timerView.expiresIn);
|
||||
|
||||
long nextUpdate = timerView.calculateAnimationDelay(timerView.startedAt, timerView.expiresIn);
|
||||
synchronized (timerView) {
|
||||
if (!timerView.visible) {
|
||||
if (timerView.visible) {
|
||||
timerView.setExpirationTime(timerView.startedAt, timerView.expiresIn);
|
||||
} else {
|
||||
timerView.stopped = true;
|
||||
return;
|
||||
}
|
||||
if (nextUpdate <= 0) {
|
||||
timerView.stopped = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Util.runOnMainDelayed(this, timerView.calculateAnimationDelay(timerView.startedAt, timerView.expiresIn));
|
||||
Util.runOnMainDelayed(this, nextUpdate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.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
|
||||
}
|
@ -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)
|
||||
|
@ -59,6 +59,7 @@ class VisibleMessageView : LinearLayout {
|
||||
const val longPressMovementTreshold = 10.0f // dp
|
||||
const val longPressDurationThreshold = 250L // ms
|
||||
const val maxDoubleTapInterval = 200L
|
||||
const val maxTimeBetweenBreaks = 5 * 60 * 1000L // 5 minutes
|
||||
}
|
||||
|
||||
// region Lifecycle
|
||||
@ -111,7 +112,7 @@ class VisibleMessageView : LinearLayout {
|
||||
senderNameTextView.visibility = View.GONE
|
||||
}
|
||||
// Date break
|
||||
val showDateBreak = (previous == null || !DateUtils.isSameHour(message.timestamp, previous.timestamp))
|
||||
val showDateBreak = (previous == null || message.timestamp - previous.timestamp > maxTimeBetweenBreaks)
|
||||
dateBreakTextView.isVisible = showDateBreak
|
||||
dateBreakTextView.text = if (showDateBreak) DateUtils.getDisplayFormattedTimeSpanString(context, Locale.getDefault(), message.timestamp) else ""
|
||||
// Timestamp
|
||||
@ -217,7 +218,9 @@ class VisibleMessageView : LinearLayout {
|
||||
if (message.expireStarted + message.expiresIn <= System.currentTimeMillis()) {
|
||||
ApplicationContext.getInstance(context).expiringMessageManager.checkSchedule()
|
||||
}
|
||||
} else if (!message.isOutgoing && !message.isMediaPending) {
|
||||
} else if (!message.isMediaPending) {
|
||||
expirationTimerView.setPercentComplete(0.0f)
|
||||
expirationTimerView.stopAnimation()
|
||||
ThreadUtils.queue {
|
||||
val expirationManager = ApplicationContext.getInstance(context).expiringMessageManager
|
||||
val id = message.getId()
|
||||
@ -225,6 +228,9 @@ class VisibleMessageView : LinearLayout {
|
||||
if (mms) DatabaseFactory.getMmsDatabase(context).markExpireStarted(id) else DatabaseFactory.getSmsDatabase(context).markExpireStarted(id)
|
||||
expirationManager.scheduleDeletion(id, mms, message.expiresIn)
|
||||
}
|
||||
} else {
|
||||
expirationTimerView.stopAnimation()
|
||||
expirationTimerView.setPercentComplete(0.0f)
|
||||
}
|
||||
} else {
|
||||
expirationTimerView.isVisible = false
|
||||
|
@ -46,14 +46,20 @@ class ConversationView : LinearLayout {
|
||||
accentView.visibility = View.VISIBLE
|
||||
} else {
|
||||
accentView.setBackgroundResource(R.color.accent)
|
||||
accentView.visibility = if (unreadCount > 0) View.VISIBLE else View.INVISIBLE
|
||||
// Using thread.isRead we can determine if the last message was our own, and display it as 'read' even though previous messages may not be
|
||||
// This would also not trigger the disappearing message timer which may or may not be desirable
|
||||
accentView.visibility = if (unreadCount > 0 && !thread.isRead) View.VISIBLE else View.INVISIBLE
|
||||
}
|
||||
val formattedUnreadCount = if (thread.isRead) {
|
||||
null
|
||||
} else {
|
||||
if (unreadCount < 100) unreadCount.toString() else "99+"
|
||||
}
|
||||
val formattedUnreadCount = if (unreadCount < 100) unreadCount.toString() else "99+"
|
||||
unreadCountTextView.text = formattedUnreadCount
|
||||
val textSize = if (unreadCount < 100) 12.0f else 9.0f
|
||||
unreadCountTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, textSize)
|
||||
unreadCountTextView.setTypeface(Typeface.DEFAULT, if (unreadCount < 100) Typeface.BOLD else Typeface.NORMAL)
|
||||
unreadCountIndicator.isVisible = (unreadCount != 0)
|
||||
unreadCountIndicator.isVisible = (unreadCount != 0 && !thread.isRead)
|
||||
val senderDisplayName = getUserDisplayName(thread.recipient)
|
||||
?: thread.recipient.address.toString()
|
||||
conversationViewDisplayNameTextView.text = senderDisplayName
|
||||
@ -69,7 +75,7 @@ class ConversationView : LinearLayout {
|
||||
val rawSnippet = thread.getDisplayBody(context)
|
||||
val snippet = highlightMentions(rawSnippet, thread.threadId, context)
|
||||
snippetTextView.text = snippet
|
||||
snippetTextView.typeface = if (unreadCount > 0) Typeface.DEFAULT_BOLD else Typeface.DEFAULT
|
||||
snippetTextView.typeface = if (unreadCount > 0 && !thread.isRead) Typeface.DEFAULT_BOLD else Typeface.DEFAULT
|
||||
snippetTextView.visibility = if (isTyping) View.GONE else View.VISIBLE
|
||||
if (isTyping) {
|
||||
typingIndicatorView.startAnimation()
|
||||
|
@ -33,15 +33,11 @@ import org.session.libsession.utilities.SSKEnvironment.ProfileManagerProtocol
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||
import org.thoughtcrime.securesms.avatar.AvatarSelection
|
||||
import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
|
||||
import org.thoughtcrime.securesms.util.UiModeUtilities
|
||||
import org.thoughtcrime.securesms.util.push
|
||||
import org.thoughtcrime.securesms.mms.GlideApp
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests
|
||||
import org.thoughtcrime.securesms.permissions.Permissions
|
||||
import org.thoughtcrime.securesms.profiles.ProfileMediaConstraints
|
||||
import org.thoughtcrime.securesms.util.BitmapDecodingException
|
||||
import org.thoughtcrime.securesms.util.BitmapUtil
|
||||
import org.thoughtcrime.securesms.util.*
|
||||
import java.io.File
|
||||
import java.security.SecureRandom
|
||||
import java.util.*
|
||||
@ -85,6 +81,7 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
chatsButton.setOnClickListener { showChatSettings() }
|
||||
sendInvitationButton.setOnClickListener { sendInvitation() }
|
||||
faqButton.setOnClickListener { showFAQ() }
|
||||
surveyButton.setOnClickListener { showSurvey() }
|
||||
helpTranslateButton.setOnClickListener { helpTranslate() }
|
||||
seedButton.setOnClickListener { showSeed() }
|
||||
clearAllDataButton.setOnClickListener { clearAllData() }
|
||||
@ -296,6 +293,16 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun showSurvey() {
|
||||
try {
|
||||
val url = "https://getsession.org/survey"
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
||||
startActivity(intent)
|
||||
} catch (e: Exception) {
|
||||
Toast.makeText(this, "Can't open URL", Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun helpTranslate() {
|
||||
try {
|
||||
val url = "https://crowdin.com/project/session-android"
|
||||
|
@ -193,6 +193,7 @@
|
||||
android:background="?android:dividerHorizontal" />
|
||||
|
||||
<TextView
|
||||
android:padding="@dimen/small_spacing"
|
||||
android:id="@+id/sendInvitationButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@ -203,6 +204,7 @@
|
||||
android:text="@string/activity_settings_invite_button_title" />
|
||||
|
||||
<TextView
|
||||
android:padding="@dimen/small_spacing"
|
||||
android:id="@+id/faqButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@ -214,6 +216,19 @@
|
||||
android:text="@string/activity_settings_faq_button_title" />
|
||||
|
||||
<TextView
|
||||
android:padding="@dimen/small_spacing"
|
||||
android:id="@+id/surveyButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/medium_spacing"
|
||||
android:textColor="@color/text"
|
||||
android:textSize="@dimen/medium_font_size"
|
||||
android:textStyle="bold"
|
||||
android:gravity="center"
|
||||
android:text="@string/activity_settings_survey_feedback" />
|
||||
|
||||
<TextView
|
||||
android:padding="@dimen/small_spacing"
|
||||
android:id="@+id/helpTranslateButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
57
app/src/main/res/layout/fragment_modal_url_bottom_sheet.xml
Normal file
57
app/src/main/res/layout/fragment_modal_url_bottom_sheet.xml
Normal file
@ -0,0 +1,57 @@
|
||||
<?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:paddingTop="@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_url"
|
||||
/>
|
||||
|
||||
<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>
|
@ -872,6 +872,7 @@
|
||||
<string name="dialog_open_url_title">Open URL?</string>
|
||||
<string name="dialog_open_url_explanation">Are you sure you want to open %s?</string>
|
||||
<string name="open">Open</string>
|
||||
<string name="copy_url">Copy URL</string>
|
||||
|
||||
<string name="dialog_link_preview_title">Enable Link Previews?</string>
|
||||
<string name="dialog_link_preview_explanation">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.</string>
|
||||
@ -897,5 +898,6 @@
|
||||
<string name="delete_message_for_me">Delete just for me</string>
|
||||
<string name="delete_message_for_everyone">Delete for everyone</string>
|
||||
<string name="delete_message_for_me_and_recipient">Delete for me and %s</string>
|
||||
<string name="activity_settings_survey_feedback">Feedback/Survey</string>
|
||||
|
||||
</resources>
|
||||
|
@ -15,23 +15,18 @@ import org.session.libsession.messaging.sending_receiving.notifications.PushNoti
|
||||
import org.session.libsession.messaging.sending_receiving.pollers.ClosedGroupPollerV2
|
||||
import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel
|
||||
import org.session.libsession.snode.SnodeAPI
|
||||
import org.session.libsession.utilities.Address
|
||||
import org.session.libsession.utilities.GroupRecord
|
||||
import org.session.libsession.utilities.*
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.session.libsession.utilities.GroupUtil
|
||||
import org.session.libsession.utilities.SSKEnvironment
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
import org.session.libsession.utilities.ProfileKeyUtil
|
||||
import org.session.libsignal.crypto.ecc.DjbECPrivateKey
|
||||
import org.session.libsignal.crypto.ecc.DjbECPublicKey
|
||||
import org.session.libsignal.crypto.ecc.ECKeyPair
|
||||
import org.session.libsignal.utilities.guava.Optional
|
||||
import org.session.libsignal.messages.SignalServiceGroup
|
||||
import org.session.libsignal.protos.SignalServiceProtos
|
||||
import org.session.libsignal.utilities.removing05PrefixIfNeeded
|
||||
import org.session.libsignal.utilities.toHexString
|
||||
import org.session.libsignal.utilities.Base64
|
||||
import org.session.libsignal.utilities.Log
|
||||
import org.session.libsignal.utilities.guava.Optional
|
||||
import org.session.libsignal.utilities.removing05PrefixIfNeeded
|
||||
import org.session.libsignal.utilities.toHexString
|
||||
import java.security.MessageDigest
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
@ -285,7 +280,8 @@ private fun handleNewClosedGroup(sender: String, sentTimestamp: Long, groupPubli
|
||||
val userPublicKey = TextSecurePreferences.getLocalNumber(context)
|
||||
// Create the group
|
||||
val groupID = GroupUtil.doubleEncodeGroupID(groupPublicKey)
|
||||
if (storage.getGroup(groupID) != null) {
|
||||
val groupExists = storage.getGroup(groupID) != null
|
||||
if (groupExists) {
|
||||
// Update the group
|
||||
if (!storage.isGroupActive(groupPublicKey)) {
|
||||
// Clear zombie list if the group wasn't active
|
||||
@ -309,10 +305,10 @@ private fun handleNewClosedGroup(sender: String, sentTimestamp: Long, groupPubli
|
||||
// Notify the PN server
|
||||
PushNotificationAPI.performOperation(PushNotificationAPI.ClosedGroupOperation.Subscribe, groupPublicKey, storage.getUserPublicKey()!!)
|
||||
// Notify the user
|
||||
if (userPublicKey == sender) {
|
||||
if (userPublicKey == sender && !groupExists) {
|
||||
val threadID = storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID))
|
||||
storage.insertOutgoingInfoMessage(context, groupID, SignalServiceGroup.Type.CREATION, name, members, admins, threadID, sentTimestamp)
|
||||
} else {
|
||||
} else if (userPublicKey != sender) {
|
||||
storage.insertIncomingInfoMessage(context, sender, groupID, SignalServiceGroup.Type.CREATION, name, members, admins, sentTimestamp)
|
||||
}
|
||||
// Start polling
|
||||
|
@ -80,6 +80,7 @@ object TextSecurePreferences {
|
||||
const val UNIVERSAL_UNIDENTIFIED_ACCESS = "pref_universal_unidentified_access"
|
||||
const val TYPING_INDICATORS = "pref_typing_indicators"
|
||||
const val LINK_PREVIEWS = "pref_link_previews"
|
||||
private const val GIF_METADATA_WARNING = "has_seen_gif_metadata_warning"
|
||||
private const val GIF_GRID_LAYOUT = "pref_gif_grid_layout"
|
||||
const val IS_USING_FCM = "pref_is_using_fcm"
|
||||
private const val FCM_TOKEN = "pref_fcm_token"
|
||||
@ -285,6 +286,16 @@ object TextSecurePreferences {
|
||||
setBooleanPreference(context, LINK_PREVIEWS, enabled)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun hasSeenGIFMetaDataWarning(context: Context): Boolean {
|
||||
return getBooleanPreference(context, GIF_METADATA_WARNING, false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setHasSeenGIFMetaDataWarning(context: Context) {
|
||||
setBooleanPreference(context, GIF_METADATA_WARNING, true)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isGifSearchInGridLayout(context: Context): Boolean {
|
||||
return getBooleanPreference(context, GIF_GRID_LAYOUT, false)
|
||||
|
Loading…
x
Reference in New Issue
Block a user