mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-27 12:05:22 +00:00
Merge branch 'pr/1451' into feature/compose-cleanup
This commit is contained in:
commit
a524933a4d
@ -322,6 +322,7 @@ dependencies {
|
|||||||
implementation "com.google.protobuf:protobuf-java:$protobufVersion"
|
implementation "com.google.protobuf:protobuf-java:$protobufVersion"
|
||||||
implementation "com.fasterxml.jackson.core:jackson-databind:$jacksonDatabindVersion"
|
implementation "com.fasterxml.jackson.core:jackson-databind:$jacksonDatabindVersion"
|
||||||
implementation "com.squareup.okhttp3:okhttp:$okhttpVersion"
|
implementation "com.squareup.okhttp3:okhttp:$okhttpVersion"
|
||||||
|
implementation "com.squareup.phrase:phrase:$phraseVersion"
|
||||||
implementation 'app.cash.copper:copper-flow:1.0.0'
|
implementation 'app.cash.copper:copper-flow:1.0.0'
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion"
|
||||||
|
@ -136,29 +136,29 @@ class SodiumUtilitiesTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun sessionIdSuccess() {
|
fun accountIdSuccess() {
|
||||||
val result = SodiumUtilities.sessionId("05$publicKey", "15$blindedPublicKey", serverPublicKey)
|
val result = SodiumUtilities.accountId("05$publicKey", "15$blindedPublicKey", serverPublicKey)
|
||||||
|
|
||||||
assertTrue(result)
|
assertTrue(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun sessionIdFailureInvalidAccountId() {
|
fun accountIdFailureInvalidAccountId() {
|
||||||
val result = SodiumUtilities.sessionId("AB$publicKey", "15$blindedPublicKey", serverPublicKey)
|
val result = SodiumUtilities.accountId("AB$publicKey", "15$blindedPublicKey", serverPublicKey)
|
||||||
|
|
||||||
assertFalse(result)
|
assertFalse(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun sessionIdFailureInvalidBlindedId() {
|
fun accountIdFailureInvalidBlindedId() {
|
||||||
val result = SodiumUtilities.sessionId("05$publicKey", "AB$blindedPublicKey", serverPublicKey)
|
val result = SodiumUtilities.accountId("05$publicKey", "AB$blindedPublicKey", serverPublicKey)
|
||||||
|
|
||||||
assertFalse(result)
|
assertFalse(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun sessionIdFailureBlindingFactor() {
|
fun accountIdFailureBlindingFactor() {
|
||||||
val result = SodiumUtilities.sessionId("05$publicKey", "15$blindedPublicKey", "Test")
|
val result = SodiumUtilities.accountId("05$publicKey", "15$blindedPublicKey", "Test")
|
||||||
|
|
||||||
assertFalse(result)
|
assertFalse(result)
|
||||||
}
|
}
|
||||||
|
@ -156,8 +156,6 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
|
|||||||
|
|
||||||
private volatile boolean isAppVisible;
|
private volatile boolean isAppVisible;
|
||||||
|
|
||||||
public boolean newAccount = false;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getSystemService(String name) {
|
public Object getSystemService(String name) {
|
||||||
if (MessagingModuleConfiguration.MESSAGING_MODULE_SERVICE.equals(name)) {
|
if (MessagingModuleConfiguration.MESSAGING_MODULE_SERVICE.equals(name)) {
|
||||||
|
@ -18,6 +18,7 @@ import org.session.libsession.utilities.Address
|
|||||||
import org.session.libsession.utilities.AppTextSecurePreferences
|
import org.session.libsession.utilities.AppTextSecurePreferences
|
||||||
import org.session.libsession.utilities.GroupUtil
|
import org.session.libsession.utilities.GroupUtil
|
||||||
import org.session.libsession.utilities.recipients.Recipient
|
import org.session.libsession.utilities.recipients.Recipient
|
||||||
|
import org.session.libsignal.utilities.Log
|
||||||
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
|
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
|
||||||
import org.thoughtcrime.securesms.mms.GlideApp
|
import org.thoughtcrime.securesms.mms.GlideApp
|
||||||
import org.thoughtcrime.securesms.mms.GlideRequests
|
import org.thoughtcrime.securesms.mms.GlideRequests
|
||||||
@ -25,6 +26,8 @@ import org.thoughtcrime.securesms.mms.GlideRequests
|
|||||||
class ProfilePictureView @JvmOverloads constructor(
|
class ProfilePictureView @JvmOverloads constructor(
|
||||||
context: Context, attrs: AttributeSet? = null
|
context: Context, attrs: AttributeSet? = null
|
||||||
) : RelativeLayout(context, attrs) {
|
) : RelativeLayout(context, attrs) {
|
||||||
|
private val TAG = "ProfilePictureView"
|
||||||
|
|
||||||
private val binding = ViewProfilePictureBinding.inflate(LayoutInflater.from(context), this)
|
private val binding = ViewProfilePictureBinding.inflate(LayoutInflater.from(context), this)
|
||||||
private val glide: GlideRequests = GlideApp.with(this)
|
private val glide: GlideRequests = GlideApp.with(this)
|
||||||
private val prefs = AppTextSecurePreferences(context)
|
private val prefs = AppTextSecurePreferences(context)
|
||||||
@ -91,7 +94,7 @@ class ProfilePictureView @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun update() {
|
fun update() {
|
||||||
val publicKey = publicKey ?: return
|
val publicKey = publicKey ?: return Log.w(TAG, "Could not find public key to update profile picture")
|
||||||
val additionalPublicKey = additionalPublicKey
|
val additionalPublicKey = additionalPublicKey
|
||||||
if (additionalPublicKey != null) {
|
if (additionalPublicKey != null) {
|
||||||
setProfilePictureIfNeeded(binding.doubleModeImageView1, publicKey, displayName)
|
setProfilePictureIfNeeded(binding.doubleModeImageView1, publicKey, displayName)
|
||||||
|
@ -89,8 +89,8 @@ private fun EnterAccountId(
|
|||||||
SessionOutlinedTextField(
|
SessionOutlinedTextField(
|
||||||
text = state.newMessageIdOrOns,
|
text = state.newMessageIdOrOns,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(horizontal = LocalDimensions.current.spacing)
|
.padding(horizontal = LocalDimensions.current.spacing),
|
||||||
.contentDescription("Session id input box"),
|
contentDescription = "Session id input box",
|
||||||
placeholder = stringResource(R.string.accountIdOrOnsEnter),
|
placeholder = stringResource(R.string.accountIdOrOnsEnter),
|
||||||
onChange = callbacks::onChange,
|
onChange = callbacks::onChange,
|
||||||
onContinue = callbacks::onContinue,
|
onContinue = callbacks::onContinue,
|
||||||
|
@ -45,7 +45,7 @@ class NewMessageFragment : Fragment() {
|
|||||||
viewModel,
|
viewModel,
|
||||||
onClose = { delegate.onDialogClosePressed() },
|
onClose = { delegate.onDialogClosePressed() },
|
||||||
onBack = { delegate.onDialogBackPressed() },
|
onBack = { delegate.onDialogBackPressed() },
|
||||||
onHelp = { requireContext().openUrl("https://sessionapp.zendesk.com/hc/en-us/articles/4439132747033-How-do-Session-ID-usernames-work") }
|
onHelp = { requireContext().openUrl("https://sessionapp.zendesk.com/hc/en-us/articles/4439132747033-How-do-Account-ID-usernames-work") }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,12 +239,12 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
|||||||
intent.getParcelableExtra<Address>(ADDRESS)?.let { it ->
|
intent.getParcelableExtra<Address>(ADDRESS)?.let { it ->
|
||||||
threadId = threadDb.getThreadIdIfExistsFor(it.serialize())
|
threadId = threadDb.getThreadIdIfExistsFor(it.serialize())
|
||||||
if (threadId == -1L) {
|
if (threadId == -1L) {
|
||||||
val sessionId = AccountId(it.serialize())
|
val accountId = AccountId(it.serialize())
|
||||||
val openGroup = lokiThreadDb.getOpenGroupChat(intent.getLongExtra(FROM_GROUP_THREAD_ID, -1))
|
val openGroup = lokiThreadDb.getOpenGroupChat(intent.getLongExtra(FROM_GROUP_THREAD_ID, -1))
|
||||||
val address = if (sessionId.prefix == IdPrefix.BLINDED && openGroup != null) {
|
val address = if (accountId.prefix == IdPrefix.BLINDED && openGroup != null) {
|
||||||
storage.getOrCreateBlindedIdMapping(sessionId.hexString, openGroup.server, openGroup.publicKey).sessionId?.let {
|
storage.getOrCreateBlindedIdMapping(accountId.hexString, openGroup.server, openGroup.publicKey).accountId?.let {
|
||||||
fromSerialized(it)
|
fromSerialized(it)
|
||||||
} ?: GroupUtil.getEncodedOpenGroupInboxID(openGroup, sessionId)
|
} ?: GroupUtil.getEncodedOpenGroupInboxID(openGroup, accountId)
|
||||||
} else {
|
} else {
|
||||||
it
|
it
|
||||||
}
|
}
|
||||||
@ -1131,8 +1131,8 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun copyAccountID(sessionId: String) {
|
override fun copyAccountID(accountId: String) {
|
||||||
val clip = ClipData.newPlainText("Account ID", sessionId)
|
val clip = ClipData.newPlainText("Account ID", accountId)
|
||||||
val manager = getSystemService(PassphraseRequiredActionBarActivity.CLIPBOARD_SERVICE) as ClipboardManager
|
val manager = getSystemService(PassphraseRequiredActionBarActivity.CLIPBOARD_SERVICE) as ClipboardManager
|
||||||
manager.setPrimaryClip(clip)
|
manager.setPrimaryClip(clip)
|
||||||
Toast.makeText(this, R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show()
|
||||||
|
@ -2,19 +2,16 @@ package org.thoughtcrime.securesms.conversation.v2.input_bar
|
|||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.Resources
|
|
||||||
import android.graphics.PointF
|
import android.graphics.PointF
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.text.Editable
|
import android.text.Editable
|
||||||
import android.text.InputType
|
import android.text.InputType
|
||||||
import android.text.TextWatcher
|
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
import android.widget.EditText
|
|
||||||
import android.widget.RelativeLayout
|
import android.widget.RelativeLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
@ -31,11 +28,8 @@ import org.thoughtcrime.securesms.conversation.v2.messages.QuoteViewDelegate
|
|||||||
import org.thoughtcrime.securesms.database.model.MessageRecord
|
import org.thoughtcrime.securesms.database.model.MessageRecord
|
||||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
||||||
import org.thoughtcrime.securesms.mms.GlideRequests
|
import org.thoughtcrime.securesms.mms.GlideRequests
|
||||||
import org.thoughtcrime.securesms.util.SimpleTextWatcher
|
|
||||||
import org.thoughtcrime.securesms.util.addTextChangedListener
|
import org.thoughtcrime.securesms.util.addTextChangedListener
|
||||||
import org.thoughtcrime.securesms.util.contains
|
import org.thoughtcrime.securesms.util.contains
|
||||||
import org.thoughtcrime.securesms.util.toDp
|
|
||||||
import org.thoughtcrime.securesms.util.toPx
|
|
||||||
|
|
||||||
// Enums to keep track of the state of our voice recording mechanism as the user can
|
// Enums to keep track of the state of our voice recording mechanism as the user can
|
||||||
// manipulate the UI faster than we can setup & teardown.
|
// manipulate the UI faster than we can setup & teardown.
|
||||||
@ -46,16 +40,24 @@ enum class VoiceRecorderState {
|
|||||||
ShuttingDownAfterRecord
|
ShuttingDownAfterRecord
|
||||||
}
|
}
|
||||||
|
|
||||||
class InputBar : RelativeLayout, InputBarEditTextDelegate, QuoteViewDelegate, LinkPreviewDraftViewDelegate,
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
|
class InputBar @JvmOverloads constructor(
|
||||||
|
context: Context,
|
||||||
|
attrs: AttributeSet? = null,
|
||||||
|
defStyleAttr: Int = 0
|
||||||
|
) : RelativeLayout(
|
||||||
|
context,
|
||||||
|
attrs,
|
||||||
|
defStyleAttr
|
||||||
|
), InputBarEditTextDelegate,
|
||||||
|
QuoteViewDelegate,
|
||||||
|
LinkPreviewDraftViewDelegate,
|
||||||
TextView.OnEditorActionListener {
|
TextView.OnEditorActionListener {
|
||||||
private lateinit var binding: ViewInputBarBinding
|
|
||||||
private val screenWidth = Resources.getSystem().displayMetrics.widthPixels
|
private var binding: ViewInputBarBinding = ViewInputBarBinding.inflate(LayoutInflater.from(context), this, true)
|
||||||
private val vMargin by lazy { toDp(4, resources) }
|
|
||||||
private val minHeight by lazy { toPx(56, resources) }
|
|
||||||
private var linkPreviewDraftView: LinkPreviewDraftView? = null
|
private var linkPreviewDraftView: LinkPreviewDraftView? = null
|
||||||
private var quoteView: QuoteView? = null
|
private var quoteView: QuoteView? = null
|
||||||
var delegate: InputBarDelegate? = null
|
var delegate: InputBarDelegate? = null
|
||||||
var additionalContentHeight = 0
|
|
||||||
var quote: MessageRecord? = null
|
var quote: MessageRecord? = null
|
||||||
var linkPreview: LinkPreview? = null
|
var linkPreview: LinkPreview? = null
|
||||||
var showInput: Boolean = true
|
var showInput: Boolean = true
|
||||||
@ -68,7 +70,7 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate, QuoteViewDelegate, Li
|
|||||||
}
|
}
|
||||||
|
|
||||||
var text: String
|
var text: String
|
||||||
get() { return binding.inputBarEditText.text?.toString() ?: "" }
|
get() = binding.inputBarEditText.text?.toString() ?: ""
|
||||||
set(value) { binding.inputBarEditText.setText(value) }
|
set(value) { binding.inputBarEditText.setText(value) }
|
||||||
|
|
||||||
// Keep track of when the user pressed the record voice message button, the duration that
|
// Keep track of when the user pressed the record voice message button, the duration that
|
||||||
@ -77,21 +79,11 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate, QuoteViewDelegate, Li
|
|||||||
var voiceMessageDurationMS = 0L
|
var voiceMessageDurationMS = 0L
|
||||||
var voiceRecorderState = VoiceRecorderState.Idle
|
var voiceRecorderState = VoiceRecorderState.Idle
|
||||||
|
|
||||||
val attachmentButtonsContainerHeight: Int
|
private val attachmentsButton = InputBarButton(context, R.drawable.ic_plus_24).apply { contentDescription = context.getString(R.string.AccessibilityId_attachments_button)}
|
||||||
get() = binding.attachmentsButtonContainer.height
|
val microphoneButton = InputBarButton(context, R.drawable.ic_microphone).apply { contentDescription = context.getString(R.string.AccessibilityId_microphone_button)}
|
||||||
|
private val sendButton = InputBarButton(context, R.drawable.ic_arrow_up, true).apply { contentDescription = context.getString(R.string.AccessibilityId_send_message_button)}
|
||||||
|
|
||||||
private val attachmentsButton by lazy { InputBarButton(context, R.drawable.ic_plus_24).apply { contentDescription = context.getString(R.string.AccessibilityId_attachments_button)} }
|
init {
|
||||||
private val microphoneButton by lazy { InputBarButton(context, R.drawable.ic_microphone).apply { contentDescription = context.getString(R.string.AccessibilityId_microphone_button)} }
|
|
||||||
private val sendButton by lazy { InputBarButton(context, R.drawable.ic_arrow_up, true).apply { contentDescription = context.getString(R.string.AccessibilityId_send_message_button)} }
|
|
||||||
|
|
||||||
// region Lifecycle
|
|
||||||
constructor(context: Context) : super(context) { initialize() }
|
|
||||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { initialize() }
|
|
||||||
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { initialize() }
|
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
|
||||||
private fun initialize() {
|
|
||||||
binding = ViewInputBarBinding.inflate(LayoutInflater.from(context), this, true)
|
|
||||||
// Attachments button
|
// Attachments button
|
||||||
binding.attachmentsButtonContainer.addView(attachmentsButton)
|
binding.attachmentsButtonContainer.addView(attachmentsButton)
|
||||||
attachmentsButton.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
|
attachmentsButton.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
|
||||||
@ -110,6 +102,7 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate, QuoteViewDelegate, Li
|
|||||||
// `microphoneButton.onUp` and tap the button then the logged output order is onUp and THEN onPress!
|
// `microphoneButton.onUp` and tap the button then the logged output order is onUp and THEN onPress!
|
||||||
microphoneButton.setOnTouchListener(object : OnTouchListener {
|
microphoneButton.setOnTouchListener(object : OnTouchListener {
|
||||||
override fun onTouch(v: View, event: MotionEvent): Boolean {
|
override fun onTouch(v: View, event: MotionEvent): Boolean {
|
||||||
|
if (!microphoneButton.snIsEnabled) return true
|
||||||
|
|
||||||
// We only handle single finger touch events so just consume the event and bail if there are more
|
// We only handle single finger touch events so just consume the event and bail if there are more
|
||||||
if (event.pointerCount > 1) return true
|
if (event.pointerCount > 1) return true
|
||||||
@ -160,12 +153,11 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate, QuoteViewDelegate, Li
|
|||||||
binding.inputBarEditText.setOnEditorActionListener(this)
|
binding.inputBarEditText.setOnEditorActionListener(this)
|
||||||
if (TextSecurePreferences.isEnterSendsEnabled(context)) {
|
if (TextSecurePreferences.isEnterSendsEnabled(context)) {
|
||||||
binding.inputBarEditText.imeOptions = EditorInfo.IME_ACTION_SEND
|
binding.inputBarEditText.imeOptions = EditorInfo.IME_ACTION_SEND
|
||||||
binding.inputBarEditText.inputType =
|
binding.inputBarEditText.inputType = InputType.TYPE_TEXT_FLAG_CAP_SENTENCES
|
||||||
InputType.TYPE_TEXT_FLAG_CAP_SENTENCES
|
|
||||||
} else {
|
} else {
|
||||||
binding.inputBarEditText.imeOptions = EditorInfo.IME_ACTION_NONE
|
binding.inputBarEditText.imeOptions = EditorInfo.IME_ACTION_NONE
|
||||||
binding.inputBarEditText.inputType =
|
binding.inputBarEditText.inputType =
|
||||||
binding.inputBarEditText.inputType or
|
binding.inputBarEditText.inputType
|
||||||
InputType.TYPE_TEXT_FLAG_CAP_SENTENCES
|
InputType.TYPE_TEXT_FLAG_CAP_SENTENCES
|
||||||
}
|
}
|
||||||
val incognitoFlag = if (TextSecurePreferences.isIncognitoKeyboardEnabled(context)) 16777216 else 0
|
val incognitoFlag = if (TextSecurePreferences.isIncognitoKeyboardEnabled(context)) 16777216 else 0
|
||||||
@ -182,9 +174,6 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate, QuoteViewDelegate, Li
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// endregion
|
|
||||||
|
|
||||||
// region Updating
|
|
||||||
override fun inputBarEditTextContentChanged(text: CharSequence) {
|
override fun inputBarEditTextContentChanged(text: CharSequence) {
|
||||||
microphoneButton.isVisible = text.trim().isEmpty()
|
microphoneButton.isVisible = text.trim().isEmpty()
|
||||||
sendButton.isVisible = microphoneButton.isGone
|
sendButton.isVisible = microphoneButton.isGone
|
||||||
@ -286,12 +275,9 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate, QuoteViewDelegate, Li
|
|||||||
fun setInputBarEditableFactory(factory: Editable.Factory) {
|
fun setInputBarEditableFactory(factory: Editable.Factory) {
|
||||||
binding.inputBarEditText.setEditableFactory(factory)
|
binding.inputBarEditText.setEditableFactory(factory)
|
||||||
}
|
}
|
||||||
|
|
||||||
// endregion
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface InputBarDelegate {
|
interface InputBarDelegate {
|
||||||
|
|
||||||
fun inputBarEditTextContentChanged(newContent: CharSequence)
|
fun inputBarEditTextContentChanged(newContent: CharSequence)
|
||||||
fun toggleAttachmentOptions()
|
fun toggleAttachmentOptions()
|
||||||
fun showVoiceMessageUI()
|
fun showVoiceMessageUI()
|
||||||
|
@ -57,7 +57,7 @@ object ConversationMenuHelper {
|
|||||||
if (!isOpenGroup && (thread.hasApprovedMe() || thread.isClosedGroupRecipient || thread.isLocalNumber)) {
|
if (!isOpenGroup && (thread.hasApprovedMe() || thread.isClosedGroupRecipient || thread.isLocalNumber)) {
|
||||||
inflater.inflate(R.menu.menu_conversation_expiration, menu)
|
inflater.inflate(R.menu.menu_conversation_expiration, menu)
|
||||||
}
|
}
|
||||||
// One-on-one chat menu allows copying the session id
|
// One-on-one chat menu allows copying the account id
|
||||||
if (thread.isContactRecipient) {
|
if (thread.isContactRecipient) {
|
||||||
inflater.inflate(R.menu.menu_conversation_copy_account_id, menu)
|
inflater.inflate(R.menu.menu_conversation_copy_account_id, menu)
|
||||||
}
|
}
|
||||||
@ -325,7 +325,7 @@ object ConversationMenuHelper {
|
|||||||
interface ConversationMenuListener {
|
interface ConversationMenuListener {
|
||||||
fun block(deleteThread: Boolean = false)
|
fun block(deleteThread: Boolean = false)
|
||||||
fun unblock()
|
fun unblock()
|
||||||
fun copyAccountID(sessionId: String)
|
fun copyAccountID(accountId: String)
|
||||||
fun copyOpenGroupUrl(thread: Recipient)
|
fun copyOpenGroupUrl(thread: Recipient)
|
||||||
fun showDisappearingMessages(thread: Recipient)
|
fun showDisappearingMessages(thread: Recipient)
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
package org.thoughtcrime.securesms.conversation.v2.utilities
|
package org.thoughtcrime.securesms.conversation.v2.utilities
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Color
|
|
||||||
import android.graphics.Typeface
|
import android.graphics.Typeface
|
||||||
import android.text.Spannable
|
import android.text.Spannable
|
||||||
import android.text.SpannableString
|
import android.text.SpannableString
|
||||||
import android.text.style.BackgroundColorSpan
|
|
||||||
import android.text.style.ForegroundColorSpan
|
import android.text.style.ForegroundColorSpan
|
||||||
import android.text.style.StyleSpan
|
import android.text.style.StyleSpan
|
||||||
import android.util.Range
|
import android.util.Range
|
||||||
import androidx.core.content.res.ResourcesCompat
|
|
||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
import nl.komponents.kovenant.combine.Tuple2
|
import nl.komponents.kovenant.combine.Tuple2
|
||||||
import org.session.libsession.messaging.contacts.Contact
|
import org.session.libsession.messaging.contacts.Contact
|
||||||
@ -22,7 +19,6 @@ import org.session.libsession.utilities.truncateIdForDisplay
|
|||||||
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
|
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
|
||||||
import org.thoughtcrime.securesms.util.RoundedBackgroundSpan
|
import org.thoughtcrime.securesms.util.RoundedBackgroundSpan
|
||||||
import org.thoughtcrime.securesms.util.getAccentColor
|
import org.thoughtcrime.securesms.util.getAccentColor
|
||||||
import org.thoughtcrime.securesms.util.toPx
|
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
object MentionUtilities {
|
object MentionUtilities {
|
||||||
@ -161,7 +157,7 @@ object MentionUtilities {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun isYou(mentionedPublicKey: String, userPublicKey: String, openGroup: OpenGroup?): Boolean {
|
private fun isYou(mentionedPublicKey: String, userPublicKey: String, openGroup: OpenGroup?): Boolean {
|
||||||
val isUserBlindedPublicKey = openGroup?.let { SodiumUtilities.sessionId(userPublicKey, mentionedPublicKey, it.publicKey) } ?: false
|
val isUserBlindedPublicKey = openGroup?.let { SodiumUtilities.accountId(userPublicKey, mentionedPublicKey, it.publicKey) } ?: false
|
||||||
return mentionedPublicKey.equals(userPublicKey, ignoreCase = true) || isUserBlindedPublicKey
|
return mentionedPublicKey.equals(userPublicKey, ignoreCase = true) || isUserBlindedPublicKey
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -31,7 +31,7 @@ class BlindedIdMappingDatabase(context: Context, helper: SQLCipherOpenHelper) :
|
|||||||
private fun readBlindedIdMapping(cursor: Cursor): BlindedIdMapping {
|
private fun readBlindedIdMapping(cursor: Cursor): BlindedIdMapping {
|
||||||
return BlindedIdMapping(
|
return BlindedIdMapping(
|
||||||
blindedId = cursor.getString(cursor.getColumnIndexOrThrow(BLINDED_PK)),
|
blindedId = cursor.getString(cursor.getColumnIndexOrThrow(BLINDED_PK)),
|
||||||
sessionId = cursor.getStringOrNull(cursor.getColumnIndexOrThrow(SESSION_PK)),
|
accountId = cursor.getStringOrNull(cursor.getColumnIndexOrThrow(SESSION_PK)),
|
||||||
serverUrl = cursor.getString(cursor.getColumnIndexOrThrow(SERVER_URL)),
|
serverUrl = cursor.getString(cursor.getColumnIndexOrThrow(SERVER_URL)),
|
||||||
serverId = cursor.getString(cursor.getColumnIndexOrThrow(SERVER_PK)),
|
serverId = cursor.getString(cursor.getColumnIndexOrThrow(SERVER_PK)),
|
||||||
)
|
)
|
||||||
@ -58,7 +58,7 @@ class BlindedIdMappingDatabase(context: Context, helper: SQLCipherOpenHelper) :
|
|||||||
try {
|
try {
|
||||||
val values = ContentValues().apply {
|
val values = ContentValues().apply {
|
||||||
put(BLINDED_PK, blindedIdMapping.blindedId)
|
put(BLINDED_PK, blindedIdMapping.blindedId)
|
||||||
put(SERVER_PK, blindedIdMapping.sessionId)
|
put(SERVER_PK, blindedIdMapping.accountId)
|
||||||
put(SERVER_URL, blindedIdMapping.serverUrl)
|
put(SERVER_URL, blindedIdMapping.serverUrl)
|
||||||
put(SERVER_PK, blindedIdMapping.serverId)
|
put(SERVER_PK, blindedIdMapping.serverId)
|
||||||
}
|
}
|
||||||
|
@ -1242,73 +1242,50 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getNotificationMmsMessageRecord(cursor: Cursor): NotificationMmsMessageRecord {
|
private fun getNotificationMmsMessageRecord(cursor: Cursor): NotificationMmsMessageRecord {
|
||||||
val id = cursor.getLong(cursor.getColumnIndexOrThrow(ID))
|
// Note: Additional details such as ADDRESS_DEVICE_ID, CONTENT_LOCATION, and TRANSACTION_ID are available if required.
|
||||||
val dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(NORMALIZED_DATE_SENT))
|
val id = cursor.getLong(cursor.getColumnIndexOrThrow(ID))
|
||||||
val dateReceived = cursor.getLong(
|
val dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(NORMALIZED_DATE_SENT))
|
||||||
cursor.getColumnIndexOrThrow(
|
val dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(NORMALIZED_DATE_RECEIVED))
|
||||||
NORMALIZED_DATE_RECEIVED
|
val threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID))
|
||||||
)
|
val mailbox = cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX))
|
||||||
)
|
val address = cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS))
|
||||||
val threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID))
|
val recipient = getRecipientFor(address)
|
||||||
val mailbox = cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX))
|
val messageSize = cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_SIZE))
|
||||||
val address = cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS))
|
val expiry = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRY))
|
||||||
val addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(ADDRESS_DEVICE_ID))
|
val status = cursor.getInt(cursor.getColumnIndexOrThrow(STATUS))
|
||||||
val recipient = getRecipientFor(address)
|
val deliveryReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(DELIVERY_RECEIPT_COUNT))
|
||||||
val contentLocation = cursor.getString(cursor.getColumnIndexOrThrow(CONTENT_LOCATION))
|
val readReceiptCount = if (isReadReceiptsEnabled(context)) cursor.getInt(cursor.getColumnIndexOrThrow(READ_RECEIPT_COUNT)) else 0
|
||||||
val transactionId = cursor.getString(cursor.getColumnIndexOrThrow(TRANSACTION_ID))
|
val hasMention = (cursor.getInt(cursor.getColumnIndexOrThrow(HAS_MENTION)) == 1)
|
||||||
val messageSize = cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_SIZE))
|
val slideDeck = SlideDeck(context, MmsNotificationAttachment(status, messageSize))
|
||||||
val expiry = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRY))
|
|
||||||
val status = cursor.getInt(cursor.getColumnIndexOrThrow(STATUS))
|
|
||||||
val deliveryReceiptCount = cursor.getInt(
|
|
||||||
cursor.getColumnIndexOrThrow(
|
|
||||||
DELIVERY_RECEIPT_COUNT
|
|
||||||
)
|
|
||||||
)
|
|
||||||
val readReceiptCount = if (isReadReceiptsEnabled(context)) cursor.getInt(cursor.getColumnIndexOrThrow(READ_RECEIPT_COUNT)) else 0
|
|
||||||
val hasMention = (cursor.getInt(cursor.getColumnIndexOrThrow(HAS_MENTION)) == 1)
|
|
||||||
val contentLocationBytes: ByteArray? = contentLocation?.takeUnless { it.isEmpty() }?.let(::toIsoBytes)
|
|
||||||
val transactionIdBytes: ByteArray? = transactionId?.takeUnless { it.isEmpty() }?.let(::toIsoBytes)
|
|
||||||
val slideDeck = SlideDeck(context, MmsNotificationAttachment(status, messageSize))
|
|
||||||
return NotificationMmsMessageRecord(
|
return NotificationMmsMessageRecord(
|
||||||
id, recipient, recipient,
|
id, recipient, recipient,
|
||||||
dateSent, dateReceived, deliveryReceiptCount, threadId,
|
dateSent, dateReceived, deliveryReceiptCount, threadId,
|
||||||
contentLocationBytes, messageSize, expiry, status,
|
messageSize, expiry, status, mailbox, slideDeck,
|
||||||
transactionIdBytes, mailbox, slideDeck,
|
|
||||||
readReceiptCount, hasMention
|
readReceiptCount, hasMention
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getMediaMmsMessageRecord(cursor: Cursor, getQuote: Boolean): MediaMmsMessageRecord {
|
private fun getMediaMmsMessageRecord(cursor: Cursor, getQuote: Boolean): MediaMmsMessageRecord {
|
||||||
val id = cursor.getLong(cursor.getColumnIndexOrThrow(ID))
|
val id = cursor.getLong(cursor.getColumnIndexOrThrow(ID))
|
||||||
val dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(NORMALIZED_DATE_SENT))
|
val dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(NORMALIZED_DATE_SENT))
|
||||||
val dateReceived = cursor.getLong(
|
val dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(NORMALIZED_DATE_RECEIVED))
|
||||||
cursor.getColumnIndexOrThrow(
|
val box = cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX))
|
||||||
NORMALIZED_DATE_RECEIVED
|
val threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID))
|
||||||
)
|
val address = cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS))
|
||||||
)
|
val addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(ADDRESS_DEVICE_ID))
|
||||||
val box = cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX))
|
val deliveryReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(DELIVERY_RECEIPT_COUNT))
|
||||||
val threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID))
|
var readReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(READ_RECEIPT_COUNT))
|
||||||
val address = cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS))
|
val body = cursor.getString(cursor.getColumnIndexOrThrow(BODY))
|
||||||
val addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(ADDRESS_DEVICE_ID))
|
val partCount = cursor.getInt(cursor.getColumnIndexOrThrow(PART_COUNT))
|
||||||
val deliveryReceiptCount = cursor.getInt(
|
val mismatchDocument = cursor.getString(cursor.getColumnIndexOrThrow(MISMATCHED_IDENTITIES))
|
||||||
cursor.getColumnIndexOrThrow(
|
val networkDocument = cursor.getString(cursor.getColumnIndexOrThrow(NETWORK_FAILURE))
|
||||||
DELIVERY_RECEIPT_COUNT
|
val subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SUBSCRIPTION_ID))
|
||||||
)
|
val expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN))
|
||||||
)
|
val expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRE_STARTED))
|
||||||
var readReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(READ_RECEIPT_COUNT))
|
val unidentified = cursor.getInt(cursor.getColumnIndexOrThrow(UNIDENTIFIED)) == 1
|
||||||
val body = cursor.getString(cursor.getColumnIndexOrThrow(BODY))
|
val hasMention = cursor.getInt(cursor.getColumnIndexOrThrow(HAS_MENTION)) == 1
|
||||||
val partCount = cursor.getInt(cursor.getColumnIndexOrThrow(PART_COUNT))
|
|
||||||
val mismatchDocument = cursor.getString(
|
|
||||||
cursor.getColumnIndexOrThrow(
|
|
||||||
MISMATCHED_IDENTITIES
|
|
||||||
)
|
|
||||||
)
|
|
||||||
val networkDocument = cursor.getString(cursor.getColumnIndexOrThrow(NETWORK_FAILURE))
|
|
||||||
val subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SUBSCRIPTION_ID))
|
|
||||||
val expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN))
|
|
||||||
val expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRE_STARTED))
|
|
||||||
val unidentified = cursor.getInt(cursor.getColumnIndexOrThrow(UNIDENTIFIED)) == 1
|
|
||||||
val hasMention = cursor.getInt(cursor.getColumnIndexOrThrow(HAS_MENTION)) == 1
|
|
||||||
if (!isReadReceiptsEnabled(context)) {
|
if (!isReadReceiptsEnabled(context)) {
|
||||||
readReceiptCount = 0
|
readReceiptCount = 0
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ class SessionContactDatabase(context: Context, helper: SQLCipherOpenHelper) : Da
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val sessionContactTable = "session_contact_database"
|
private const val sessionContactTable = "session_contact_database"
|
||||||
const val accountID = "account_id"
|
const val accountID = "session_id"
|
||||||
const val name = "name"
|
const val name = "name"
|
||||||
const val nickname = "nickname"
|
const val nickname = "nickname"
|
||||||
const val profilePictureURL = "profile_picture_url"
|
const val profilePictureURL = "profile_picture_url"
|
||||||
@ -42,12 +42,12 @@ class SessionContactDatabase(context: Context, helper: SQLCipherOpenHelper) : Da
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getContacts(sessionIDs: Collection<String>): List<Contact> {
|
fun getContacts(accountIDs: Collection<String>): List<Contact> {
|
||||||
val database = databaseHelper.readableDatabase
|
val database = databaseHelper.readableDatabase
|
||||||
return database.getAll(
|
return database.getAll(
|
||||||
sessionContactTable,
|
sessionContactTable,
|
||||||
"$accountID IN (SELECT value FROM json_each(?))",
|
"$accountID IN (SELECT value FROM json_each(?))",
|
||||||
arrayOf(JSONArray(sessionIDs).toString())
|
arrayOf(JSONArray(accountIDs).toString())
|
||||||
) { cursor -> contactFromCursor(cursor) }
|
) { cursor -> contactFromCursor(cursor) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,8 +56,7 @@ class SessionContactDatabase(context: Context, helper: SQLCipherOpenHelper) : Da
|
|||||||
return database.getAll(sessionContactTable, null, null) { cursor ->
|
return database.getAll(sessionContactTable, null, null) { cursor ->
|
||||||
contactFromCursor(cursor)
|
contactFromCursor(cursor)
|
||||||
}.filter { contact ->
|
}.filter { contact ->
|
||||||
val sessionId = AccountId(contact.accountID)
|
contact.accountID.let(::AccountId).prefix == IdPrefix.STANDARD
|
||||||
sessionId.prefix == IdPrefix.STANDARD
|
|
||||||
}.toSet()
|
}.toSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import java.security.MessageDigest
|
|||||||
import network.loki.messenger.libsession_util.ConfigBase
|
import network.loki.messenger.libsession_util.ConfigBase
|
||||||
import network.loki.messenger.libsession_util.ConfigBase.Companion.PRIORITY_HIDDEN
|
import network.loki.messenger.libsession_util.ConfigBase.Companion.PRIORITY_HIDDEN
|
||||||
import network.loki.messenger.libsession_util.ConfigBase.Companion.PRIORITY_PINNED
|
import network.loki.messenger.libsession_util.ConfigBase.Companion.PRIORITY_PINNED
|
||||||
|
import network.loki.messenger.libsession_util.ConfigBase.Companion.PRIORITY_VISIBLE
|
||||||
import network.loki.messenger.libsession_util.Contacts
|
import network.loki.messenger.libsession_util.Contacts
|
||||||
import network.loki.messenger.libsession_util.ConversationVolatileConfig
|
import network.loki.messenger.libsession_util.ConversationVolatileConfig
|
||||||
import network.loki.messenger.libsession_util.UserGroupsConfig
|
import network.loki.messenger.libsession_util.UserGroupsConfig
|
||||||
@ -111,12 +112,12 @@ open class Storage(
|
|||||||
if (address.isGroup) {
|
if (address.isGroup) {
|
||||||
val groups = configFactory.userGroups ?: return
|
val groups = configFactory.userGroups ?: return
|
||||||
if (address.isClosedGroup) {
|
if (address.isClosedGroup) {
|
||||||
val sessionId = GroupUtil.doubleDecodeGroupId(address.serialize())
|
val accountId = GroupUtil.doubleDecodeGroupId(address.serialize())
|
||||||
val closedGroup = getGroup(address.toGroupString())
|
val closedGroup = getGroup(address.toGroupString())
|
||||||
if (closedGroup != null && closedGroup.isActive) {
|
if (closedGroup != null && closedGroup.isActive) {
|
||||||
val legacyGroup = groups.getOrConstructLegacyGroupInfo(sessionId)
|
val legacyGroup = groups.getOrConstructLegacyGroupInfo(accountId)
|
||||||
groups.set(legacyGroup)
|
groups.set(legacyGroup)
|
||||||
val newVolatileParams = volatile.getOrConstructLegacyGroup(sessionId).copy(
|
val newVolatileParams = volatile.getOrConstructLegacyGroup(accountId).copy(
|
||||||
lastRead = SnodeAPI.nowWithOffset,
|
lastRead = SnodeAPI.nowWithOffset,
|
||||||
)
|
)
|
||||||
volatile.set(newVolatileParams)
|
volatile.set(newVolatileParams)
|
||||||
@ -132,11 +133,11 @@ open class Storage(
|
|||||||
if (getUserPublicKey() != address.serialize()) {
|
if (getUserPublicKey() != address.serialize()) {
|
||||||
val contacts = configFactory.contacts ?: return
|
val contacts = configFactory.contacts ?: return
|
||||||
contacts.upsertContact(address.serialize()) {
|
contacts.upsertContact(address.serialize()) {
|
||||||
priority = ConfigBase.PRIORITY_VISIBLE
|
priority = PRIORITY_VISIBLE
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val userProfile = configFactory.user ?: return
|
val userProfile = configFactory.user ?: return
|
||||||
userProfile.setNtsPriority(ConfigBase.PRIORITY_VISIBLE)
|
userProfile.setNtsPriority(PRIORITY_VISIBLE)
|
||||||
DatabaseComponent.get(context).threadDatabase().setHasSent(threadId, true)
|
DatabaseComponent.get(context).threadDatabase().setHasSent(threadId, true)
|
||||||
}
|
}
|
||||||
val newVolatileParams = volatile.getOrConstructOneToOne(address.serialize())
|
val newVolatileParams = volatile.getOrConstructOneToOne(address.serialize())
|
||||||
@ -149,9 +150,9 @@ open class Storage(
|
|||||||
if (address.isGroup) {
|
if (address.isGroup) {
|
||||||
val groups = configFactory.userGroups ?: return
|
val groups = configFactory.userGroups ?: return
|
||||||
if (address.isClosedGroup) {
|
if (address.isClosedGroup) {
|
||||||
val sessionId = GroupUtil.doubleDecodeGroupId(address.serialize())
|
val accountId = GroupUtil.doubleDecodeGroupId(address.serialize())
|
||||||
volatile.eraseLegacyClosedGroup(sessionId)
|
volatile.eraseLegacyClosedGroup(accountId)
|
||||||
groups.eraseLegacyGroup(sessionId)
|
groups.eraseLegacyGroup(accountId)
|
||||||
} else if (address.isCommunity) {
|
} else if (address.isCommunity) {
|
||||||
// these should be removed in the group leave / handling new configs
|
// these should be removed in the group leave / handling new configs
|
||||||
Log.w("Loki", "Thread delete called for open group address, expecting to be handled elsewhere")
|
Log.w("Loki", "Thread delete called for open group address, expecting to be handled elsewhere")
|
||||||
@ -265,10 +266,8 @@ open class Storage(
|
|||||||
}
|
}
|
||||||
// otherwise recipient is one to one
|
// otherwise recipient is one to one
|
||||||
recipient.isContactRecipient -> {
|
recipient.isContactRecipient -> {
|
||||||
// don't process non-standard session IDs though
|
// don't process non-standard account IDs though
|
||||||
val sessionId = AccountId(recipient.address.serialize())
|
if (AccountId(recipient.address.serialize()).prefix != IdPrefix.STANDARD) return
|
||||||
if (sessionId.prefix != IdPrefix.STANDARD) return
|
|
||||||
|
|
||||||
config.getOrConstructOneToOne(recipient.address.serialize())
|
config.getOrConstructOneToOne(recipient.address.serialize())
|
||||||
}
|
}
|
||||||
else -> throw NullPointerException("Weren't expecting to have a convo with address ${recipient.address.serialize()}")
|
else -> throw NullPointerException("Weren't expecting to have a convo with address ${recipient.address.serialize()}")
|
||||||
@ -299,8 +298,8 @@ open class Storage(
|
|||||||
var messageID: Long? = null
|
var messageID: Long? = null
|
||||||
val senderAddress = fromSerialized(message.sender!!)
|
val senderAddress = fromSerialized(message.sender!!)
|
||||||
val isUserSender = (message.sender!! == getUserPublicKey())
|
val isUserSender = (message.sender!! == getUserPublicKey())
|
||||||
val isUserBlindedSender = message.threadID?.takeIf { it >= 0 }?.let { getOpenGroup(it)?.publicKey }
|
val isUserBlindedSender = message.threadID?.takeIf { it >= 0 }?.let(::getOpenGroup)?.publicKey
|
||||||
?.let { SodiumUtilities.sessionId(getUserPublicKey()!!, message.sender!!, it) } ?: false
|
?.let { SodiumUtilities.accountId(getUserPublicKey()!!, message.sender!!, it) } ?: false
|
||||||
val group: Optional<SignalServiceGroup> = when {
|
val group: Optional<SignalServiceGroup> = when {
|
||||||
openGroupID != null -> Optional.of(SignalServiceGroup(openGroupID.toByteArray(), SignalServiceGroup.GroupType.PUBLIC_CHAT))
|
openGroupID != null -> Optional.of(SignalServiceGroup(openGroupID.toByteArray(), SignalServiceGroup.GroupType.PUBLIC_CHAT))
|
||||||
groupPublicKey != null -> {
|
groupPublicKey != null -> {
|
||||||
@ -540,7 +539,7 @@ open class Storage(
|
|||||||
val extracted = convos.all()
|
val extracted = convos.all()
|
||||||
for (conversation in extracted) {
|
for (conversation in extracted) {
|
||||||
val threadId = when (conversation) {
|
val threadId = when (conversation) {
|
||||||
is Conversation.OneToOne -> getThreadIdFor(conversation.sessionId, null, null, createThread = false)
|
is Conversation.OneToOne -> getThreadIdFor(conversation.accountId, null, null, createThread = false)
|
||||||
is Conversation.LegacyGroup -> getThreadIdFor("", conversation.groupId,null, createThread = false)
|
is Conversation.LegacyGroup -> getThreadIdFor("", conversation.groupId,null, createThread = false)
|
||||||
is Conversation.Community -> getThreadIdFor("",null, "${conversation.baseCommunityInfo.baseUrl.removeSuffix("/")}.${conversation.baseCommunityInfo.room}", createThread = false)
|
is Conversation.Community -> getThreadIdFor("",null, "${conversation.baseCommunityInfo.baseUrl.removeSuffix("/")}.${conversation.baseCommunityInfo.room}", createThread = false)
|
||||||
}
|
}
|
||||||
@ -571,7 +570,7 @@ open class Storage(
|
|||||||
val existingJoinUrls = existingCommunities.values.map { it.joinURL }
|
val existingJoinUrls = existingCommunities.values.map { it.joinURL }
|
||||||
|
|
||||||
val existingClosedGroups = getAllGroups(includeInactive = true).filter { it.isClosedGroup }
|
val existingClosedGroups = getAllGroups(includeInactive = true).filter { it.isClosedGroup }
|
||||||
val lgcIds = lgc.map { it.sessionId }
|
val lgcIds = lgc.map { it.accountId }
|
||||||
val toDeleteClosedGroups = existingClosedGroups.filter { group ->
|
val toDeleteClosedGroups = existingClosedGroups.filter { group ->
|
||||||
GroupUtil.doubleDecodeGroupId(group.encodedId) !in lgcIds
|
GroupUtil.doubleDecodeGroupId(group.encodedId) !in lgcIds
|
||||||
}
|
}
|
||||||
@ -605,8 +604,8 @@ open class Storage(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (group in lgc) {
|
for (group in lgc) {
|
||||||
val groupId = GroupUtil.doubleEncodeGroupID(group.sessionId)
|
val groupId = GroupUtil.doubleEncodeGroupID(group.accountId)
|
||||||
val existingGroup = existingClosedGroups.firstOrNull { GroupUtil.doubleDecodeGroupId(it.encodedId) == group.sessionId }
|
val existingGroup = existingClosedGroups.firstOrNull { GroupUtil.doubleDecodeGroupId(it.encodedId) == group.accountId }
|
||||||
val existingThread = existingGroup?.let { getThreadId(existingGroup.encodedId) }
|
val existingThread = existingGroup?.let { getThreadId(existingGroup.encodedId) }
|
||||||
if (existingGroup != null) {
|
if (existingGroup != null) {
|
||||||
if (group.priority == PRIORITY_HIDDEN && existingThread != null) {
|
if (group.priority == PRIORITY_HIDDEN && existingThread != null) {
|
||||||
@ -625,19 +624,19 @@ open class Storage(
|
|||||||
createGroup(groupId, title, admins + members, null, null, admins, formationTimestamp)
|
createGroup(groupId, title, admins + members, null, null, admins, formationTimestamp)
|
||||||
setProfileSharing(Address.fromSerialized(groupId), true)
|
setProfileSharing(Address.fromSerialized(groupId), true)
|
||||||
// Add the group to the user's set of public keys to poll for
|
// Add the group to the user's set of public keys to poll for
|
||||||
addClosedGroupPublicKey(group.sessionId)
|
addClosedGroupPublicKey(group.accountId)
|
||||||
// Store the encryption key pair
|
// Store the encryption key pair
|
||||||
val keyPair = ECKeyPair(DjbECPublicKey(group.encPubKey), DjbECPrivateKey(group.encSecKey))
|
val keyPair = ECKeyPair(DjbECPublicKey(group.encPubKey), DjbECPrivateKey(group.encSecKey))
|
||||||
addClosedGroupEncryptionKeyPair(keyPair, group.sessionId, SnodeAPI.nowWithOffset)
|
addClosedGroupEncryptionKeyPair(keyPair, group.accountId, SnodeAPI.nowWithOffset)
|
||||||
// Notify the PN server
|
// Notify the PN server
|
||||||
PushRegistryV1.subscribeGroup(group.sessionId, publicKey = localUserPublicKey)
|
PushRegistryV1.subscribeGroup(group.accountId, publicKey = localUserPublicKey)
|
||||||
// Notify the user
|
// Notify the user
|
||||||
val threadID = getOrCreateThreadIdFor(Address.fromSerialized(groupId))
|
val threadID = getOrCreateThreadIdFor(Address.fromSerialized(groupId))
|
||||||
threadDb.setDate(threadID, formationTimestamp)
|
threadDb.setDate(threadID, formationTimestamp)
|
||||||
insertOutgoingInfoMessage(context, groupId, SignalServiceGroup.Type.CREATION, title, members.map { it.serialize() }, admins.map { it.serialize() }, threadID, formationTimestamp)
|
insertOutgoingInfoMessage(context, groupId, SignalServiceGroup.Type.CREATION, title, members.map { it.serialize() }, admins.map { it.serialize() }, threadID, formationTimestamp)
|
||||||
// Don't create config group here, it's from a config update
|
// Don't create config group here, it's from a config update
|
||||||
// Start polling
|
// Start polling
|
||||||
ClosedGroupPollerV2.shared.startPolling(group.sessionId)
|
ClosedGroupPollerV2.shared.startPolling(group.accountId)
|
||||||
}
|
}
|
||||||
getThreadId(Address.fromSerialized(groupId))?.let {
|
getThreadId(Address.fromSerialized(groupId))?.let {
|
||||||
setExpirationConfiguration(
|
setExpirationConfiguration(
|
||||||
@ -938,10 +937,10 @@ open class Storage(
|
|||||||
groupVolatileConfig.lastRead = formationTimestamp
|
groupVolatileConfig.lastRead = formationTimestamp
|
||||||
volatiles.set(groupVolatileConfig)
|
volatiles.set(groupVolatileConfig)
|
||||||
val groupInfo = GroupInfo.LegacyGroupInfo(
|
val groupInfo = GroupInfo.LegacyGroupInfo(
|
||||||
sessionId = groupPublicKey,
|
accountId = groupPublicKey,
|
||||||
name = name,
|
name = name,
|
||||||
members = members,
|
members = members,
|
||||||
priority = ConfigBase.PRIORITY_VISIBLE,
|
priority = PRIORITY_VISIBLE,
|
||||||
encPubKey = (encryptionKeyPair.publicKey as DjbECPublicKey).publicKey, // 'serialize()' inserts an extra byte
|
encPubKey = (encryptionKeyPair.publicKey as DjbECPublicKey).publicKey, // 'serialize()' inserts an extra byte
|
||||||
encSecKey = encryptionKeyPair.privateKey.serialize(),
|
encSecKey = encryptionKeyPair.privateKey.serialize(),
|
||||||
disappearingTimer = expirationTimer.toLong(),
|
disappearingTimer = expirationTimer.toLong(),
|
||||||
@ -975,7 +974,7 @@ open class Storage(
|
|||||||
members = membersMap,
|
members = membersMap,
|
||||||
encPubKey = (latestKeyPair.publicKey as DjbECPublicKey).publicKey, // 'serialize()' inserts an extra byte
|
encPubKey = (latestKeyPair.publicKey as DjbECPublicKey).publicKey, // 'serialize()' inserts an extra byte
|
||||||
encSecKey = latestKeyPair.privateKey.serialize(),
|
encSecKey = latestKeyPair.privateKey.serialize(),
|
||||||
priority = if (isPinned(threadID)) PRIORITY_PINNED else ConfigBase.PRIORITY_VISIBLE,
|
priority = if (isPinned(threadID)) PRIORITY_PINNED else PRIORITY_VISIBLE,
|
||||||
disappearingTimer = getExpirationConfiguration(threadID)?.expiryMode?.expirySeconds ?: 0L,
|
disappearingTimer = getExpirationConfiguration(threadID)?.expiryMode?.expirySeconds ?: 0L,
|
||||||
joinedAt = (existingGroup.formationTimestamp / 1000L)
|
joinedAt = (existingGroup.formationTimestamp / 1000L)
|
||||||
)
|
)
|
||||||
@ -1209,7 +1208,7 @@ open class Storage(
|
|||||||
val mappingDb = DatabaseComponent.get(context).blindedIdMappingDatabase()
|
val mappingDb = DatabaseComponent.get(context).blindedIdMappingDatabase()
|
||||||
val moreContacts = contacts.filter { contact ->
|
val moreContacts = contacts.filter { contact ->
|
||||||
val id = AccountId(contact.id)
|
val id = AccountId(contact.id)
|
||||||
id.prefix?.isBlinded() == false || mappingDb.getBlindedIdMapping(contact.id).none { it.sessionId != null }
|
id.prefix?.isBlinded() == false || mappingDb.getBlindedIdMapping(contact.id).none { it.accountId != null }
|
||||||
}
|
}
|
||||||
val profileManager = SSKEnvironment.shared.profileManager
|
val profileManager = SSKEnvironment.shared.profileManager
|
||||||
moreContacts.forEach { contact ->
|
moreContacts.forEach { contact ->
|
||||||
@ -1262,7 +1261,7 @@ open class Storage(
|
|||||||
val mappingDb = DatabaseComponent.get(context).blindedIdMappingDatabase()
|
val mappingDb = DatabaseComponent.get(context).blindedIdMappingDatabase()
|
||||||
val moreContacts = contacts.filter { contact ->
|
val moreContacts = contacts.filter { contact ->
|
||||||
val id = AccountId(contact.publicKey)
|
val id = AccountId(contact.publicKey)
|
||||||
id.prefix != IdPrefix.BLINDED || mappingDb.getBlindedIdMapping(contact.publicKey).none { it.sessionId != null }
|
id.prefix != IdPrefix.BLINDED || mappingDb.getBlindedIdMapping(contact.publicKey).none { it.accountId != null }
|
||||||
}
|
}
|
||||||
for (contact in moreContacts) {
|
for (contact in moreContacts) {
|
||||||
val address = fromSerialized(contact.publicKey)
|
val address = fromSerialized(contact.publicKey)
|
||||||
@ -1329,25 +1328,25 @@ open class Storage(
|
|||||||
val threadRecipient = getRecipientForThread(threadID) ?: return
|
val threadRecipient = getRecipientForThread(threadID) ?: return
|
||||||
if (threadRecipient.isLocalNumber) {
|
if (threadRecipient.isLocalNumber) {
|
||||||
val user = configFactory.user ?: return
|
val user = configFactory.user ?: return
|
||||||
user.setNtsPriority(if (isPinned) PRIORITY_PINNED else ConfigBase.PRIORITY_VISIBLE)
|
user.setNtsPriority(if (isPinned) PRIORITY_PINNED else PRIORITY_VISIBLE)
|
||||||
} else if (threadRecipient.isContactRecipient) {
|
} else if (threadRecipient.isContactRecipient) {
|
||||||
val contacts = configFactory.contacts ?: return
|
val contacts = configFactory.contacts ?: return
|
||||||
contacts.upsertContact(threadRecipient.address.serialize()) {
|
contacts.upsertContact(threadRecipient.address.serialize()) {
|
||||||
priority = if (isPinned) PRIORITY_PINNED else ConfigBase.PRIORITY_VISIBLE
|
priority = if (isPinned) PRIORITY_PINNED else PRIORITY_VISIBLE
|
||||||
}
|
}
|
||||||
} else if (threadRecipient.isGroupRecipient) {
|
} else if (threadRecipient.isGroupRecipient) {
|
||||||
val groups = configFactory.userGroups ?: return
|
val groups = configFactory.userGroups ?: return
|
||||||
if (threadRecipient.isClosedGroupRecipient) {
|
if (threadRecipient.isClosedGroupRecipient) {
|
||||||
val sessionId = GroupUtil.doubleDecodeGroupId(threadRecipient.address.serialize())
|
threadRecipient.address.serialize()
|
||||||
val newGroupInfo = groups.getOrConstructLegacyGroupInfo(sessionId).copy (
|
.let(GroupUtil::doubleDecodeGroupId)
|
||||||
priority = if (isPinned) PRIORITY_PINNED else ConfigBase.PRIORITY_VISIBLE
|
.let(groups::getOrConstructLegacyGroupInfo)
|
||||||
)
|
.copy (priority = if (isPinned) PRIORITY_PINNED else PRIORITY_VISIBLE)
|
||||||
groups.set(newGroupInfo)
|
.let(groups::set)
|
||||||
} else if (threadRecipient.isCommunityRecipient) {
|
} else if (threadRecipient.isCommunityRecipient) {
|
||||||
val openGroup = getOpenGroup(threadID) ?: return
|
val openGroup = getOpenGroup(threadID) ?: return
|
||||||
val (baseUrl, room, pubKeyHex) = BaseCommunityInfo.parseFullUrl(openGroup.joinURL) ?: return
|
val (baseUrl, room, pubKeyHex) = BaseCommunityInfo.parseFullUrl(openGroup.joinURL) ?: return
|
||||||
val newGroupInfo = groups.getOrConstructCommunityInfo(baseUrl, room, Hex.toStringCondensed(pubKeyHex)).copy (
|
val newGroupInfo = groups.getOrConstructCommunityInfo(baseUrl, room, Hex.toStringCondensed(pubKeyHex)).copy (
|
||||||
priority = if (isPinned) PRIORITY_PINNED else ConfigBase.PRIORITY_VISIBLE
|
priority = if (isPinned) PRIORITY_PINNED else PRIORITY_VISIBLE
|
||||||
)
|
)
|
||||||
groups.set(newGroupInfo)
|
groups.set(newGroupInfo)
|
||||||
}
|
}
|
||||||
@ -1505,10 +1504,10 @@ open class Storage(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (mapping in mappings) {
|
for (mapping in mappings) {
|
||||||
if (!SodiumUtilities.sessionId(senderPublicKey, mapping.value.blindedId, mapping.value.serverId)) {
|
if (!SodiumUtilities.accountId(senderPublicKey, mapping.value.blindedId, mapping.value.serverId)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
mappingDb.addBlindedIdMapping(mapping.value.copy(sessionId = senderPublicKey))
|
mappingDb.addBlindedIdMapping(mapping.value.copy(accountId = senderPublicKey))
|
||||||
|
|
||||||
val blindedThreadId = threadDB.getOrCreateThreadIdFor(Recipient.from(context, fromSerialized(mapping.key), false))
|
val blindedThreadId = threadDB.getOrCreateThreadIdFor(Recipient.from(context, fromSerialized(mapping.key), false))
|
||||||
mmsDb.updateThreadId(blindedThreadId, threadId)
|
mmsDb.updateThreadId(blindedThreadId, threadId)
|
||||||
@ -1614,20 +1613,20 @@ open class Storage(
|
|||||||
): BlindedIdMapping {
|
): BlindedIdMapping {
|
||||||
val db = DatabaseComponent.get(context).blindedIdMappingDatabase()
|
val db = DatabaseComponent.get(context).blindedIdMappingDatabase()
|
||||||
val mapping = db.getBlindedIdMapping(blindedId).firstOrNull() ?: BlindedIdMapping(blindedId, null, server, serverPublicKey)
|
val mapping = db.getBlindedIdMapping(blindedId).firstOrNull() ?: BlindedIdMapping(blindedId, null, server, serverPublicKey)
|
||||||
if (mapping.sessionId != null) {
|
if (mapping.accountId != null) {
|
||||||
return mapping
|
return mapping
|
||||||
}
|
}
|
||||||
getAllContacts().forEach { contact ->
|
getAllContacts().forEach { contact ->
|
||||||
val sessionId = AccountId(contact.accountID)
|
val accountId = AccountId(contact.accountID)
|
||||||
if (sessionId.prefix == IdPrefix.STANDARD && SodiumUtilities.sessionId(sessionId.hexString, blindedId, serverPublicKey)) {
|
if (accountId.prefix == IdPrefix.STANDARD && SodiumUtilities.accountId(accountId.hexString, blindedId, serverPublicKey)) {
|
||||||
val contactMapping = mapping.copy(sessionId = sessionId.hexString)
|
val contactMapping = mapping.copy(accountId = accountId.hexString)
|
||||||
db.addBlindedIdMapping(contactMapping)
|
db.addBlindedIdMapping(contactMapping)
|
||||||
return contactMapping
|
return contactMapping
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
db.getBlindedIdMappingsExceptFor(server).forEach {
|
db.getBlindedIdMappingsExceptFor(server).forEach {
|
||||||
if (SodiumUtilities.sessionId(it.sessionId!!, blindedId, serverPublicKey)) {
|
if (SodiumUtilities.accountId(it.accountId!!, blindedId, serverPublicKey)) {
|
||||||
val otherMapping = mapping.copy(sessionId = it.sessionId)
|
val otherMapping = mapping.copy(accountId = it.accountId)
|
||||||
db.addBlindedIdMapping(otherMapping)
|
db.addBlindedIdMapping(otherMapping)
|
||||||
return otherMapping
|
return otherMapping
|
||||||
}
|
}
|
||||||
|
@ -1,113 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2012 Moxie Marlinspike
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package org.thoughtcrime.securesms.database.model;
|
|
||||||
|
|
||||||
import static java.util.Collections.emptyList;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.text.SpannableString;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import org.session.libsession.utilities.recipients.Recipient;
|
|
||||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
|
||||||
import org.thoughtcrime.securesms.database.SmsDatabase.Status;
|
|
||||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
|
||||||
|
|
||||||
import network.loki.messenger.R;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the message record model for MMS messages that are
|
|
||||||
* notifications (ie: they're pointers to undownloaded media).
|
|
||||||
*
|
|
||||||
* @author Moxie Marlinspike
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class NotificationMmsMessageRecord extends MmsMessageRecord {
|
|
||||||
private final byte[] contentLocation;
|
|
||||||
private final long messageSize;
|
|
||||||
private final long expiry;
|
|
||||||
private final int status;
|
|
||||||
private final byte[] transactionId;
|
|
||||||
|
|
||||||
public NotificationMmsMessageRecord(long id, Recipient conversationRecipient,
|
|
||||||
Recipient individualRecipient,
|
|
||||||
long dateSent, long dateReceived, int deliveryReceiptCount,
|
|
||||||
long threadId, byte[] contentLocation, long messageSize,
|
|
||||||
long expiry, int status, byte[] transactionId, long mailbox,
|
|
||||||
SlideDeck slideDeck, int readReceiptCount, boolean hasMention)
|
|
||||||
{
|
|
||||||
super(id, "", conversationRecipient, individualRecipient,
|
|
||||||
dateSent, dateReceived, threadId, Status.STATUS_NONE, deliveryReceiptCount, mailbox,
|
|
||||||
emptyList(), emptyList(),
|
|
||||||
0, 0, slideDeck, readReceiptCount, null, emptyList(), emptyList(), false, emptyList(), hasMention);
|
|
||||||
|
|
||||||
this.contentLocation = contentLocation;
|
|
||||||
this.messageSize = messageSize;
|
|
||||||
this.expiry = expiry;
|
|
||||||
this.status = status;
|
|
||||||
this.transactionId = transactionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getTransactionId() {
|
|
||||||
return transactionId;
|
|
||||||
}
|
|
||||||
public int getStatus() {
|
|
||||||
return this.status;
|
|
||||||
}
|
|
||||||
public byte[] getContentLocation() {
|
|
||||||
return contentLocation;
|
|
||||||
}
|
|
||||||
public long getMessageSize() {
|
|
||||||
return (messageSize + 1023) / 1024;
|
|
||||||
}
|
|
||||||
public long getExpiration() {
|
|
||||||
return expiry * 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isOutgoing() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isPending() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isMmsNotification() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isMediaPending() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SpannableString getDisplayBody(@NonNull Context context) {
|
|
||||||
if (status == MmsDatabase.Status.DOWNLOAD_INITIALIZED) {
|
|
||||||
return emphasisAdded(context.getString(R.string.NotificationMmsMessageRecord_multimedia_message));
|
|
||||||
} else if (status == MmsDatabase.Status.DOWNLOAD_CONNECTING) {
|
|
||||||
return emphasisAdded(context.getString(R.string.NotificationMmsMessageRecord_downloading_mms_message));
|
|
||||||
} else {
|
|
||||||
return emphasisAdded(context.getString(R.string.NotificationMmsMessageRecord_error_downloading_mms_message));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012 Moxie Marlinspike
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.thoughtcrime.securesms.database.model
|
||||||
|
|
||||||
|
import org.session.libsession.utilities.recipients.Recipient
|
||||||
|
import org.thoughtcrime.securesms.database.SmsDatabase
|
||||||
|
import org.thoughtcrime.securesms.mms.SlideDeck
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the message record model for MMS messages that are
|
||||||
|
* notifications (ie: they're pointers to undownloaded media).
|
||||||
|
*
|
||||||
|
* @author Moxie Marlinspike
|
||||||
|
*/
|
||||||
|
class NotificationMmsMessageRecord(
|
||||||
|
id: Long, conversationRecipient: Recipient?,
|
||||||
|
individualRecipient: Recipient?,
|
||||||
|
dateSent: Long,
|
||||||
|
dateReceived: Long,
|
||||||
|
deliveryReceiptCount: Int,
|
||||||
|
threadId: Long,
|
||||||
|
private val messageSize: Long,
|
||||||
|
private val expiry: Long,
|
||||||
|
val status: Int,
|
||||||
|
mailbox: Long,
|
||||||
|
slideDeck: SlideDeck?,
|
||||||
|
readReceiptCount: Int,
|
||||||
|
hasMention: Boolean
|
||||||
|
) : MmsMessageRecord(
|
||||||
|
id, "", conversationRecipient, individualRecipient,
|
||||||
|
dateSent, dateReceived, threadId, SmsDatabase.Status.STATUS_NONE, deliveryReceiptCount, mailbox,
|
||||||
|
emptyList(), emptyList(),
|
||||||
|
0, 0, slideDeck!!, readReceiptCount, null, emptyList(), emptyList(), false, emptyList(), hasMention
|
||||||
|
) {
|
||||||
|
fun getMessageSize(): Long {
|
||||||
|
return (messageSize + 1023) / 1024
|
||||||
|
}
|
||||||
|
|
||||||
|
val expiration: Long
|
||||||
|
get() = expiry * 1000
|
||||||
|
|
||||||
|
override fun isOutgoing(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isPending(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isMmsNotification(): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isMediaPending(): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,6 @@ import android.content.Context
|
|||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.graphics.Typeface
|
import android.graphics.Typeface
|
||||||
import android.graphics.drawable.ColorDrawable
|
import android.graphics.drawable.ColorDrawable
|
||||||
import android.text.SpannableString
|
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
@ -23,7 +22,6 @@ import org.thoughtcrime.securesms.database.RecipientDatabase.NOTIFY_TYPE_ALL
|
|||||||
import org.thoughtcrime.securesms.database.RecipientDatabase.NOTIFY_TYPE_NONE
|
import org.thoughtcrime.securesms.database.RecipientDatabase.NOTIFY_TYPE_NONE
|
||||||
import org.thoughtcrime.securesms.database.model.ThreadRecord
|
import org.thoughtcrime.securesms.database.model.ThreadRecord
|
||||||
import org.thoughtcrime.securesms.dependencies.ConfigFactory
|
import org.thoughtcrime.securesms.dependencies.ConfigFactory
|
||||||
import org.thoughtcrime.securesms.mms.GlideRequests
|
|
||||||
import org.thoughtcrime.securesms.util.DateUtils
|
import org.thoughtcrime.securesms.util.DateUtils
|
||||||
import org.thoughtcrime.securesms.util.getAccentColor
|
import org.thoughtcrime.securesms.util.getAccentColor
|
||||||
import org.thoughtcrime.securesms.util.getConversationUnread
|
import org.thoughtcrime.securesms.util.getConversationUnread
|
||||||
@ -51,7 +49,7 @@ class ConversationView : LinearLayout {
|
|||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// region Updating
|
// region Updating
|
||||||
fun bind(thread: ThreadRecord, isTyping: Boolean, glide: GlideRequests) {
|
fun bind(thread: ThreadRecord, isTyping: Boolean) {
|
||||||
this.thread = thread
|
this.thread = thread
|
||||||
if (thread.isPinned) {
|
if (thread.isPinned) {
|
||||||
binding.conversationViewDisplayNameTextView.setCompoundDrawablesRelativeWithIntrinsicBounds(
|
binding.conversationViewDisplayNameTextView.setCompoundDrawablesRelativeWithIntrinsicBounds(
|
||||||
@ -142,11 +140,10 @@ class ConversationView : LinearLayout {
|
|||||||
else -> recipient.toShortString() // Internally uses the Contact API
|
else -> recipient.toShortString() // Internally uses the Contact API
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ThreadRecord.getSnippet(): CharSequence =
|
private fun ThreadRecord.getSnippet(): CharSequence = listOfNotNull(
|
||||||
concatSnippet(getSnippetPrefix(), getDisplayBody(context))
|
getSnippetPrefix(),
|
||||||
|
getDisplayBody(context)
|
||||||
private fun concatSnippet(prefix: CharSequence?, body: CharSequence): CharSequence =
|
).joinToString(": ")
|
||||||
prefix?.let { TextUtils.concat(it, ": ", body) } ?: body
|
|
||||||
|
|
||||||
private fun ThreadRecord.getSnippetPrefix(): CharSequence? = when {
|
private fun ThreadRecord.getSnippetPrefix(): CharSequence? = when {
|
||||||
recipient.isLocalNumber || lastMessage?.isControlMessage == true -> null
|
recipient.isLocalNumber || lastMessage?.isControlMessage == true -> null
|
||||||
|
@ -8,7 +8,6 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.Telephony.Mms.Addr
|
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
@ -23,6 +22,7 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.filter
|
||||||
import kotlinx.coroutines.flow.filterNotNull
|
import kotlinx.coroutines.flow.filterNotNull
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
@ -59,6 +59,7 @@ import org.thoughtcrime.securesms.dependencies.DatabaseComponent
|
|||||||
import org.thoughtcrime.securesms.groups.OpenGroupManager
|
import org.thoughtcrime.securesms.groups.OpenGroupManager
|
||||||
import org.thoughtcrime.securesms.home.search.GlobalSearchAdapter
|
import org.thoughtcrime.securesms.home.search.GlobalSearchAdapter
|
||||||
import org.thoughtcrime.securesms.home.search.GlobalSearchInputLayout
|
import org.thoughtcrime.securesms.home.search.GlobalSearchInputLayout
|
||||||
|
import org.thoughtcrime.securesms.home.search.GlobalSearchResult
|
||||||
import org.thoughtcrime.securesms.home.search.GlobalSearchViewModel
|
import org.thoughtcrime.securesms.home.search.GlobalSearchViewModel
|
||||||
import org.thoughtcrime.securesms.messagerequests.MessageRequestsActivity
|
import org.thoughtcrime.securesms.messagerequests.MessageRequestsActivity
|
||||||
import org.thoughtcrime.securesms.mms.GlideApp
|
import org.thoughtcrime.securesms.mms.GlideApp
|
||||||
@ -85,6 +86,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
|
|||||||
GlobalSearchInputLayout.GlobalSearchInputLayoutListener {
|
GlobalSearchInputLayout.GlobalSearchInputLayoutListener {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
const val NEW_ACCOUNT = "HomeActivity_NEW_ACCOUNT"
|
||||||
const val FROM_ONBOARDING = "HomeActivity_FROM_ONBOARDING"
|
const val FROM_ONBOARDING = "HomeActivity_FROM_ONBOARDING"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,6 +137,8 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val isNewAccount: Boolean get() = intent.getBooleanExtra(FROM_ONBOARDING, false)
|
||||||
|
|
||||||
// region Lifecycle
|
// region Lifecycle
|
||||||
override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) {
|
override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) {
|
||||||
super.onCreate(savedInstanceState, isReady)
|
super.onCreate(savedInstanceState, isReady)
|
||||||
@ -175,7 +179,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
|
|||||||
|
|
||||||
// Set up empty state view
|
// Set up empty state view
|
||||||
binding.emptyStateContainer.setThemedContent {
|
binding.emptyStateContainer.setThemedContent {
|
||||||
EmptyView(ApplicationContext.getInstance(this).newAccount)
|
EmptyView(isNewAccount)
|
||||||
}
|
}
|
||||||
|
|
||||||
IP2Country.configureIfNeeded(this@HomeActivity)
|
IP2Country.configureIfNeeded(this@HomeActivity)
|
||||||
@ -240,67 +244,25 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
|
|||||||
}
|
}
|
||||||
// Get group results and display them
|
// Get group results and display them
|
||||||
launch {
|
launch {
|
||||||
globalSearchViewModel.result.collect { result ->
|
globalSearchViewModel.result.map { result ->
|
||||||
if (result.query.isEmpty()) {
|
result.query to when {
|
||||||
class NamedValue<T>(val name: String?, val value: T)
|
result.query.isEmpty() -> buildList {
|
||||||
|
add(GlobalSearchAdapter.Model.Header(R.string.contacts))
|
||||||
// Unknown is temporarily to be grouped together with numbers title.
|
add(GlobalSearchAdapter.Model.SavedMessages(publicKey))
|
||||||
// https://optf.atlassian.net/browse/SES-2287
|
addAll(result.groupedContacts)
|
||||||
val numbersTitle = "#"
|
}
|
||||||
val unknownTitle = numbersTitle
|
else -> buildList {
|
||||||
|
result.contactAndGroupList.takeUnless { it.isEmpty() }?.let {
|
||||||
listOf(
|
add(GlobalSearchAdapter.Model.Header(R.string.contacts))
|
||||||
GlobalSearchAdapter.Model.Header(R.string.contacts),
|
addAll(it)
|
||||||
GlobalSearchAdapter.Model.SavedMessages(publicKey)
|
}
|
||||||
) + result.contacts
|
result.messageResults.takeUnless { it.isEmpty() }?.let {
|
||||||
// Remove ourself, we're shown above.
|
add(GlobalSearchAdapter.Model.Header(R.string.global_search_messages))
|
||||||
.filter { it.accountID != publicKey }
|
addAll(it)
|
||||||
// Get the name that we will display and sort by, and uppercase it to
|
|
||||||
// help with sorting and we need the char uppercased later.
|
|
||||||
.map { (it.nickname?.takeIf(String::isNotEmpty) ?: it.name?.takeIf(String::isNotEmpty))
|
|
||||||
.let { name -> NamedValue(name?.uppercase(), it) } }
|
|
||||||
// Digits are all grouped under a #, the rest are grouped by their first character.uppercased()
|
|
||||||
// If there is no name, they go under Unknown
|
|
||||||
.groupBy { it.name?.run { first().takeUnless(Char::isDigit)?.toString() ?: numbersTitle } ?: unknownTitle }
|
|
||||||
// place the # at the end, after all the names starting with alphabetic chars
|
|
||||||
.toSortedMap(compareBy {
|
|
||||||
when (it) {
|
|
||||||
unknownTitle -> Char.MAX_VALUE
|
|
||||||
numbersTitle -> Char.MAX_VALUE - 1
|
|
||||||
else -> it.first()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// Flatten the map of char to lists into an actual List that can be displayed.
|
|
||||||
.flatMap { (key, contacts) ->
|
|
||||||
listOf(
|
|
||||||
GlobalSearchAdapter.Model.SubHeader(key)
|
|
||||||
) + contacts.sortedBy { it.name ?: it.value.accountID }.map { it.value }.map { GlobalSearchAdapter.Model.Contact(it, it.accountID == publicKey) }
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
val contactAndGroupList = result.contacts.map { GlobalSearchAdapter.Model.Contact(it, it.accountID == publicKey) } +
|
|
||||||
result.threads.map(GlobalSearchAdapter.Model::GroupConversation)
|
|
||||||
|
|
||||||
val contactResults = contactAndGroupList.toMutableList()
|
|
||||||
|
|
||||||
if (contactResults.isNotEmpty()) {
|
|
||||||
contactResults.add(0, GlobalSearchAdapter.Model.Header(R.string.conversations))
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
val unreadThreadMap = result.messages
|
}.collectLatest(globalSearchAdapter::setNewData)
|
||||||
.map { it.threadId }.toSet()
|
|
||||||
.associateWith { mmsSmsDatabase.getUnreadCount(it) }
|
|
||||||
|
|
||||||
val messageResults: MutableList<GlobalSearchAdapter.Model> = result.messages
|
|
||||||
.map { GlobalSearchAdapter.Model.Message(it, unreadThreadMap[it.threadId] ?: 0, it.conversationRecipient.isLocalNumber) }
|
|
||||||
.toMutableList()
|
|
||||||
|
|
||||||
if (messageResults.isNotEmpty()) {
|
|
||||||
messageResults.add(0, GlobalSearchAdapter.Model.Header(R.string.global_search_messages))
|
|
||||||
}
|
|
||||||
|
|
||||||
contactResults + messageResults
|
|
||||||
}.let { globalSearchAdapter.setNewData(result.query, it) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EventBus.getDefault().register(this@HomeActivity)
|
EventBus.getDefault().register(this@HomeActivity)
|
||||||
@ -318,6 +280,54 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val GlobalSearchResult.groupedContacts: List<GlobalSearchAdapter.Model> get() {
|
||||||
|
class NamedValue<T>(val name: String?, val value: T)
|
||||||
|
|
||||||
|
// Unknown is temporarily to be grouped together with numbers title.
|
||||||
|
// https://optf.atlassian.net/browse/SES-2287
|
||||||
|
val numbersTitle = "#"
|
||||||
|
val unknownTitle = numbersTitle
|
||||||
|
|
||||||
|
return contacts
|
||||||
|
// Remove ourself, we're shown above.
|
||||||
|
.filter { it.accountID != publicKey }
|
||||||
|
// Get the name that we will display and sort by, and uppercase it to
|
||||||
|
// help with sorting and we need the char uppercased later.
|
||||||
|
.map { (it.nickname?.takeIf(String::isNotEmpty) ?: it.name?.takeIf(String::isNotEmpty))
|
||||||
|
.let { name -> NamedValue(name?.uppercase(), it) } }
|
||||||
|
// Digits are all grouped under a #, the rest are grouped by their first character.uppercased()
|
||||||
|
// If there is no name, they go under Unknown
|
||||||
|
.groupBy { it.name?.run { first().takeUnless(Char::isDigit)?.toString() ?: numbersTitle } ?: unknownTitle }
|
||||||
|
// place the # at the end, after all the names starting with alphabetic chars
|
||||||
|
.toSortedMap(compareBy {
|
||||||
|
when (it) {
|
||||||
|
unknownTitle -> Char.MAX_VALUE
|
||||||
|
numbersTitle -> Char.MAX_VALUE - 1
|
||||||
|
else -> it.first()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// Flatten the map of char to lists into an actual List that can be displayed.
|
||||||
|
.flatMap { (key, contacts) ->
|
||||||
|
listOf(
|
||||||
|
GlobalSearchAdapter.Model.SubHeader(key)
|
||||||
|
) + contacts.sortedBy { it.name ?: it.value.accountID }.map { it.value }.map { GlobalSearchAdapter.Model.Contact(it, it.nickname ?: it.name, it.accountID == publicKey) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val GlobalSearchResult.contactAndGroupList: List<GlobalSearchAdapter.Model> get() =
|
||||||
|
contacts.map { GlobalSearchAdapter.Model.Contact(it, it.nickname ?: it.name, it.accountID == publicKey) } +
|
||||||
|
threads.map(GlobalSearchAdapter.Model::GroupConversation)
|
||||||
|
|
||||||
|
private val GlobalSearchResult.messageResults: List<GlobalSearchAdapter.Model> get() {
|
||||||
|
val unreadThreadMap = messages
|
||||||
|
.map { it.threadId }.toSet()
|
||||||
|
.associateWith { mmsSmsDatabase.getUnreadCount(it) }
|
||||||
|
|
||||||
|
return messages.map {
|
||||||
|
GlobalSearchAdapter.Model.Message(it, unreadThreadMap[it.threadId] ?: 0, it.conversationRecipient.isLocalNumber)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onInputFocusChanged(hasFocus: Boolean) {
|
override fun onInputFocusChanged(hasFocus: Boolean) {
|
||||||
setSearchShown(hasFocus || binding.globalSearchInputLayout.query.value.isNotEmpty())
|
setSearchShown(hasFocus || binding.globalSearchInputLayout.query.value.isNotEmpty())
|
||||||
}
|
}
|
||||||
@ -629,9 +639,10 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.startHomeActivity() {
|
fun Context.startHomeActivity(isNewAccount: Boolean) {
|
||||||
Intent(this, HomeActivity::class.java).apply {
|
Intent(this, HomeActivity::class.java).apply {
|
||||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||||
|
putExtra(HomeActivity.NEW_ACCOUNT, true)
|
||||||
putExtra(HomeActivity.FROM_ONBOARDING, true)
|
putExtra(HomeActivity.FROM_ONBOARDING, true)
|
||||||
}.also(::startActivity)
|
}.also(::startActivity)
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package org.thoughtcrime.securesms.home
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.ListUpdateCallback
|
import androidx.recyclerview.widget.ListUpdateCallback
|
||||||
@ -12,8 +11,6 @@ import network.loki.messenger.R
|
|||||||
import network.loki.messenger.databinding.ViewMessageRequestBannerBinding
|
import network.loki.messenger.databinding.ViewMessageRequestBannerBinding
|
||||||
import org.thoughtcrime.securesms.dependencies.ConfigFactory
|
import org.thoughtcrime.securesms.dependencies.ConfigFactory
|
||||||
import org.thoughtcrime.securesms.mms.GlideRequests
|
import org.thoughtcrime.securesms.mms.GlideRequests
|
||||||
import org.thoughtcrime.securesms.util.DateUtils
|
|
||||||
import java.util.Locale
|
|
||||||
|
|
||||||
class HomeAdapter(
|
class HomeAdapter(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
@ -115,7 +112,7 @@ class HomeAdapter(
|
|||||||
val offset = if (hasHeaderView()) position - 1 else position
|
val offset = if (hasHeaderView()) position - 1 else position
|
||||||
val thread = data.threads[offset]
|
val thread = data.threads[offset]
|
||||||
val isTyping = data.typingThreadIDs.contains(thread.threadId)
|
val isTyping = data.typingThreadIDs.contains(thread.threadId)
|
||||||
holder.view.bind(thread, isTyping, glide)
|
holder.view.bind(thread, isTyping)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,8 @@ class GlobalSearchAdapter(private val modelCallback: (Model)->Unit): RecyclerVie
|
|||||||
private var data: List<Model> = listOf()
|
private var data: List<Model> = listOf()
|
||||||
private var query: String? = null
|
private var query: String? = null
|
||||||
|
|
||||||
|
fun setNewData(data: Pair<String, List<Model>>) = setNewData(data.first, data.second)
|
||||||
|
|
||||||
fun setNewData(query: String, newData: List<Model>) {
|
fun setNewData(query: String, newData: List<Model>) {
|
||||||
val diffResult = DiffUtil.calculateDiff(GlobalSearchDiff(this.query, query, data, newData))
|
val diffResult = DiffUtil.calculateDiff(GlobalSearchDiff(this.query, query, data, newData))
|
||||||
this.query = query
|
this.query = query
|
||||||
@ -134,7 +136,7 @@ class GlobalSearchAdapter(private val modelCallback: (Model)->Unit): RecyclerVie
|
|||||||
constructor(title: String): this(GetString(title))
|
constructor(title: String): this(GetString(title))
|
||||||
}
|
}
|
||||||
data class SavedMessages(val currentUserPublicKey: String): Model()
|
data class SavedMessages(val currentUserPublicKey: String): Model()
|
||||||
data class Contact(val contact: ContactModel, val isSelf: Boolean): Model()
|
data class Contact(val contact: ContactModel, val name: String?, val isSelf: Boolean): Model()
|
||||||
data class GroupConversation(val groupRecord: GroupRecord): Model()
|
data class GroupConversation(val groupRecord: GroupRecord): Model()
|
||||||
data class Message(val messageResult: MessageResult, val unread: Int, val isSelf: Boolean): Model()
|
data class Message(val messageResult: MessageResult, val unread: Int, val isSelf: Boolean): Model()
|
||||||
}
|
}
|
||||||
|
@ -6,22 +6,18 @@ import dagger.hilt.android.lifecycle.HiltViewModel
|
|||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.channels.BufferOverflow
|
import kotlinx.coroutines.channels.BufferOverflow
|
||||||
import kotlinx.coroutines.channels.Channel
|
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.buffer
|
import kotlinx.coroutines.flow.buffer
|
||||||
import kotlinx.coroutines.flow.combine
|
|
||||||
import kotlinx.coroutines.flow.consumeAsFlow
|
|
||||||
import kotlinx.coroutines.flow.flatMapLatest
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.flow.launchIn
|
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.mapLatest
|
import kotlinx.coroutines.flow.mapLatest
|
||||||
import kotlinx.coroutines.flow.merge
|
import kotlinx.coroutines.flow.merge
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.plus
|
import kotlinx.coroutines.plus
|
||||||
import org.session.libsignal.utilities.SettableFuture
|
import org.session.libsignal.utilities.SettableFuture
|
||||||
@ -35,16 +31,32 @@ import javax.inject.Inject
|
|||||||
class GlobalSearchViewModel @Inject constructor(
|
class GlobalSearchViewModel @Inject constructor(
|
||||||
private val searchRepository: SearchRepository,
|
private val searchRepository: SearchRepository,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
private val scope = viewModelScope + SupervisorJob()
|
||||||
private val executor = viewModelScope + SupervisorJob()
|
|
||||||
|
|
||||||
private val _result: MutableStateFlow<GlobalSearchResult> = MutableStateFlow(GlobalSearchResult.EMPTY)
|
|
||||||
|
|
||||||
val result: StateFlow<GlobalSearchResult> = _result
|
|
||||||
|
|
||||||
private val refreshes = MutableSharedFlow<Unit>()
|
private val refreshes = MutableSharedFlow<Unit>()
|
||||||
|
private val _queryText = MutableStateFlow<CharSequence>("")
|
||||||
|
|
||||||
private val _queryText: MutableStateFlow<CharSequence> = MutableStateFlow("")
|
val result = _queryText
|
||||||
|
.reEmit(refreshes)
|
||||||
|
.buffer(onBufferOverflow = BufferOverflow.DROP_OLDEST)
|
||||||
|
.mapLatest { query ->
|
||||||
|
if (query.trim().isEmpty()) {
|
||||||
|
// searching for 05 as contactDb#getAllContacts was not returning contacts
|
||||||
|
// without a nickname/name who haven't approved us.
|
||||||
|
GlobalSearchResult(query.toString(), searchRepository.queryContacts("05").first.toList())
|
||||||
|
} else {
|
||||||
|
// User input delay in case we get a new query within a few hundred ms this
|
||||||
|
// coroutine will be cancelled and the expensive query will not be run.
|
||||||
|
delay(300)
|
||||||
|
val settableFuture = SettableFuture<SearchResult>()
|
||||||
|
searchRepository.query(query.toString(), settableFuture::set)
|
||||||
|
try {
|
||||||
|
// search repository doesn't play nicely with suspend functions (yet)
|
||||||
|
settableFuture.get(10_000, TimeUnit.MILLISECONDS).toGlobalSearchResult()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
GlobalSearchResult(query.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun setQuery(charSequence: CharSequence) {
|
fun setQuery(charSequence: CharSequence) {
|
||||||
_queryText.value = charSequence
|
_queryText.value = charSequence
|
||||||
@ -55,34 +67,6 @@ class GlobalSearchViewModel @Inject constructor(
|
|||||||
refreshes.emit(Unit)
|
refreshes.emit(Unit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
|
||||||
_queryText
|
|
||||||
.reEmit(refreshes)
|
|
||||||
.buffer(onBufferOverflow = BufferOverflow.DROP_OLDEST)
|
|
||||||
.mapLatest { query ->
|
|
||||||
if (query.trim().isEmpty()) {
|
|
||||||
// searching for 05 as contactDb#getAllContacts was not returning contacts
|
|
||||||
// without a nickname/name who haven't approved us.
|
|
||||||
GlobalSearchResult(query.toString(), searchRepository.queryContacts("05").first.toList())
|
|
||||||
} else {
|
|
||||||
// User input delay in case we get a new query within a few hundred ms this
|
|
||||||
// coroutine will be cancelled and the expensive query will not be run.
|
|
||||||
delay(300)
|
|
||||||
val settableFuture = SettableFuture<SearchResult>()
|
|
||||||
searchRepository.query(query.toString(), settableFuture::set)
|
|
||||||
try {
|
|
||||||
// search repository doesn't play nicely with suspend functions (yet)
|
|
||||||
settableFuture.get(10_000, TimeUnit.MILLISECONDS).toGlobalSearchResult()
|
|
||||||
} catch (e: Exception) {
|
|
||||||
GlobalSearchResult(query.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.onEach { result ->
|
|
||||||
// update the latest _result value
|
|
||||||
_result.value = result
|
|
||||||
}.launchIn(executor)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -34,13 +34,13 @@ class MessageRequestView : LinearLayout {
|
|||||||
// region Updating
|
// region Updating
|
||||||
fun bind(thread: ThreadRecord, glide: GlideRequests) {
|
fun bind(thread: ThreadRecord, glide: GlideRequests) {
|
||||||
this.thread = thread
|
this.thread = thread
|
||||||
val senderDisplayName = getUserDisplayName(thread.recipient)
|
|
||||||
?: thread.recipient.address.toString()
|
val senderDisplayName = getUserDisplayName(thread.recipient) ?: thread.recipient.address.toString()
|
||||||
|
|
||||||
binding.displayNameTextView.text = senderDisplayName
|
binding.displayNameTextView.text = senderDisplayName
|
||||||
binding.timestampTextView.text = DateUtils.getDisplayFormattedTimeSpanString(context, Locale.getDefault(), thread.date)
|
binding.timestampTextView.text = DateUtils.getDisplayFormattedTimeSpanString(context, Locale.getDefault(), thread.date)
|
||||||
val rawSnippet = thread.getDisplayBody(context)
|
|
||||||
val snippet = highlightMentions(
|
val snippet = highlightMentions(
|
||||||
text = rawSnippet,
|
text = thread.getDisplayBody(context),
|
||||||
formatOnly = true, // no styling here, only text formatting
|
formatOnly = true, // no styling here, only text formatting
|
||||||
threadID = thread.threadId,
|
threadID = thread.threadId,
|
||||||
context = context
|
context = context
|
||||||
|
@ -16,24 +16,23 @@
|
|||||||
*/
|
*/
|
||||||
package org.thoughtcrime.securesms.mms;
|
package org.thoughtcrime.securesms.mms;
|
||||||
|
|
||||||
|
import static org.session.libsession.utilities.StringSubstitutionConstants.EMOJI_KEY;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Resources.Theme;
|
import android.content.res.Resources.Theme;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import androidx.annotation.DrawableRes;
|
import androidx.annotation.DrawableRes;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import com.squareup.phrase.Phrase;
|
||||||
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentTransferProgress;
|
import java.security.SecureRandom;
|
||||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
import network.loki.messenger.R;
|
||||||
import org.session.libsignal.utilities.guava.Optional;
|
|
||||||
|
|
||||||
import org.session.libsession.messaging.sending_receiving.attachments.Attachment;
|
import org.session.libsession.messaging.sending_receiving.attachments.Attachment;
|
||||||
|
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentTransferProgress;
|
||||||
import org.session.libsession.messaging.sending_receiving.attachments.UriAttachment;
|
import org.session.libsession.messaging.sending_receiving.attachments.UriAttachment;
|
||||||
import org.session.libsession.utilities.Util;
|
import org.session.libsession.utilities.Util;
|
||||||
|
import org.session.libsignal.utilities.guava.Optional;
|
||||||
import java.security.SecureRandom;
|
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||||
|
|
||||||
import network.loki.messenger.R;
|
|
||||||
|
|
||||||
public abstract class Slide {
|
public abstract class Slide {
|
||||||
|
|
||||||
@ -72,20 +71,23 @@ public abstract class Slide {
|
|||||||
return Optional.fromNullable("🎤 " + attachmentString);
|
return Optional.fromNullable("🎤 " + attachmentString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Optional.fromNullable(emojiForMimeType() + attachmentString);
|
String txt = Phrase.from(context, R.string.attachmentsNotification)
|
||||||
|
.put(EMOJI_KEY, emojiForMimeType())
|
||||||
|
.format().toString();
|
||||||
|
return Optional.fromNullable(txt);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String emojiForMimeType() {
|
private String emojiForMimeType() {
|
||||||
if (MediaUtil.isImage(attachment)) {
|
if (MediaUtil.isImage(attachment)) {
|
||||||
return "📷 ";
|
return "📷";
|
||||||
} else if (MediaUtil.isVideo(attachment)) {
|
} else if (MediaUtil.isVideo(attachment)) {
|
||||||
return "🎥 ";
|
return "🎥";
|
||||||
} else if (MediaUtil.isAudio(attachment)) {
|
} else if (MediaUtil.isAudio(attachment)) {
|
||||||
return "🎧 ";
|
return "🎧";
|
||||||
} else if (MediaUtil.isFile(attachment)) {
|
} else if (MediaUtil.isFile(attachment)) {
|
||||||
return "📎 ";
|
return "📎";
|
||||||
} else {
|
} else {
|
||||||
return "🎡 ";
|
return "🎡"; // `isGif`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,20 +157,20 @@ public abstract class Slide {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static Attachment constructAttachmentFromUri(@NonNull Context context,
|
protected static Attachment constructAttachmentFromUri(@NonNull Context context,
|
||||||
@NonNull Uri uri,
|
@NonNull Uri uri,
|
||||||
@NonNull String defaultMime,
|
@NonNull String defaultMime,
|
||||||
long size,
|
long size,
|
||||||
int width,
|
int width,
|
||||||
int height,
|
int height,
|
||||||
boolean hasThumbnail,
|
boolean hasThumbnail,
|
||||||
@Nullable String fileName,
|
@Nullable String fileName,
|
||||||
@Nullable String caption,
|
@Nullable String caption,
|
||||||
boolean voiceNote,
|
boolean voiceNote,
|
||||||
boolean quote)
|
boolean quote)
|
||||||
{
|
{
|
||||||
String resolvedType = Optional.fromNullable(MediaUtil.getMimeType(context, uri)).or(defaultMime);
|
String resolvedType = Optional.fromNullable(MediaUtil.getMimeType(context, uri)).or(defaultMime);
|
||||||
String fastPreflightId = String.valueOf(new SecureRandom().nextLong());
|
String fastPreflightId = String.valueOf(new SecureRandom().nextLong());
|
||||||
return new UriAttachment(uri,
|
return new UriAttachment(uri,
|
||||||
hasThumbnail ? uri : null,
|
hasThumbnail ? uri : null,
|
||||||
resolvedType,
|
resolvedType,
|
||||||
|
@ -24,6 +24,7 @@ import androidx.annotation.Nullable;
|
|||||||
import com.annimon.stream.Stream;
|
import com.annimon.stream.Stream;
|
||||||
|
|
||||||
import org.session.libsession.messaging.sending_receiving.attachments.Attachment;
|
import org.session.libsession.messaging.sending_receiving.attachments.Attachment;
|
||||||
|
import org.session.libsignal.utilities.Log;
|
||||||
import org.session.libsignal.utilities.guava.Optional;
|
import org.session.libsignal.utilities.guava.Optional;
|
||||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||||
|
|
||||||
@ -47,8 +48,7 @@ public class SlideDeck {
|
|||||||
if (slide != null) slides.add(slide);
|
if (slide != null) slides.add(slide);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SlideDeck() {
|
public SlideDeck() { }
|
||||||
}
|
|
||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
slides.clear();
|
slides.clear();
|
||||||
@ -65,7 +65,6 @@ public class SlideDeck {
|
|||||||
body = slideBody.get();
|
body = slideBody.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ import android.net.Uri;
|
|||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.service.notification.StatusBarNotification;
|
import android.service.notification.StatusBarNotification;
|
||||||
|
import android.text.SpannableString;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
@ -145,9 +146,8 @@ public class DefaultMessageNotifier implements MessageNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void notifyMessagesPending(Context context) {
|
public void notifyMessagesPending(Context context) {
|
||||||
if (!TextSecurePreferences.isNotificationsEnabled(context)) {
|
|
||||||
return;
|
if (!TextSecurePreferences.isNotificationsEnabled(context)) { return; }
|
||||||
}
|
|
||||||
|
|
||||||
PendingMessageNotificationBuilder builder = new PendingMessageNotificationBuilder(context, TextSecurePreferences.getNotificationPrivacy(context));
|
PendingMessageNotificationBuilder builder = new PendingMessageNotificationBuilder(context, TextSecurePreferences.getNotificationPrivacy(context));
|
||||||
ServiceUtil.getNotificationManager(context).notify(PENDING_MESSAGES_ID, builder.build());
|
ServiceUtil.getNotificationManager(context).notify(PENDING_MESSAGES_ID, builder.build());
|
||||||
@ -185,9 +185,9 @@ public class DefaultMessageNotifier implements MessageNotifier {
|
|||||||
for (StatusBarNotification notification : activeNotifications) {
|
for (StatusBarNotification notification : activeNotifications) {
|
||||||
boolean validNotification = false;
|
boolean validNotification = false;
|
||||||
|
|
||||||
if (notification.getId() != SUMMARY_NOTIFICATION_ID &&
|
if (notification.getId() != SUMMARY_NOTIFICATION_ID &&
|
||||||
notification.getId() != KeyCachingService.SERVICE_RUNNING_ID &&
|
notification.getId() != KeyCachingService.SERVICE_RUNNING_ID &&
|
||||||
notification.getId() != FOREGROUND_ID &&
|
notification.getId() != FOREGROUND_ID &&
|
||||||
notification.getId() != PENDING_MESSAGES_ID)
|
notification.getId() != PENDING_MESSAGES_ID)
|
||||||
{
|
{
|
||||||
for (NotificationItem item : notificationState.getNotifications()) {
|
for (NotificationItem item : notificationState.getNotifications()) {
|
||||||
@ -197,9 +197,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!validNotification) {
|
if (!validNotification) { notifications.cancel(notification.getId()); }
|
||||||
notifications.cancel(notification.getId());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
@ -231,7 +229,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
|
|||||||
@Override
|
@Override
|
||||||
public void updateNotification(@NonNull Context context, long threadId, boolean signal)
|
public void updateNotification(@NonNull Context context, long threadId, boolean signal)
|
||||||
{
|
{
|
||||||
boolean isVisible = visibleThread == threadId;
|
boolean isVisible = visibleThread == threadId;
|
||||||
|
|
||||||
ThreadDatabase threads = DatabaseComponent.get(context).threadDatabase();
|
ThreadDatabase threads = DatabaseComponent.get(context).threadDatabase();
|
||||||
Recipient recipient = threads.getRecipientForThreadId(threadId);
|
Recipient recipient = threads.getRecipientForThreadId(threadId);
|
||||||
@ -348,14 +346,19 @@ public class DefaultMessageNotifier implements MessageNotifier {
|
|||||||
builder.setThread(notifications.get(0).getRecipient());
|
builder.setThread(notifications.get(0).getRecipient());
|
||||||
builder.setMessageCount(notificationState.getMessageCount());
|
builder.setMessageCount(notificationState.getMessageCount());
|
||||||
|
|
||||||
// TODO: Removing highlighting mentions in the notification because this context is the libsession one which
|
CharSequence builderCS = text == null ? "" : text;
|
||||||
// TODO: doesn't have access to the `R.attr.message_sent_text_color` and `R.attr.message_received_text_color`
|
SpannableString ss = MentionUtilities.highlightMentions(
|
||||||
// TODO: attributes to perform the colour lookup. Also, it makes little sense to highlight the mentions using
|
builderCS,
|
||||||
// TODO: the app theme as it may result in insufficient contrast with the notification background which will
|
false,
|
||||||
// TODO: be using the SYSTEM theme.
|
false,
|
||||||
builder.setPrimaryMessageBody(recipient, notifications.get(0).getIndividualRecipient(),
|
true,
|
||||||
//MentionUtilities.highlightMentions(text == null ? "" : text, notifications.get(0).getThreadId(), context), // Removing hightlighting mentions -ACL
|
bundled ? notifications.get(0).getThreadId() : 0,
|
||||||
text == null ? "" : text,
|
context
|
||||||
|
);
|
||||||
|
|
||||||
|
builder.setPrimaryMessageBody(recipient,
|
||||||
|
notifications.get(0).getIndividualRecipient(),
|
||||||
|
ss,
|
||||||
notifications.get(0).getSlideDeck());
|
notifications.get(0).getSlideDeck());
|
||||||
|
|
||||||
builder.setContentIntent(notifications.get(0).getPendingIntent(context));
|
builder.setContentIntent(notifications.get(0).getPendingIntent(context));
|
||||||
@ -505,24 +508,39 @@ public class DefaultMessageNotifier implements MessageNotifier {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this is a message request from an unknown user..
|
||||||
if (messageRequest) {
|
if (messageRequest) {
|
||||||
body = SpanUtil.italic(context.getString(R.string.message_requests_notification));
|
body = SpanUtil.italic(context.getString(R.string.message_requests_notification));
|
||||||
|
|
||||||
|
// If we received some manner of notification but Session is locked..
|
||||||
} else if (KeyCachingService.isLocked(context)) {
|
} else if (KeyCachingService.isLocked(context)) {
|
||||||
body = SpanUtil.italic(context.getString(R.string.MessageNotifier_locked_message));
|
body = SpanUtil.italic(context.getString(R.string.MessageNotifier_locked_message));
|
||||||
|
|
||||||
|
// ----- All further cases assume we know the contact and that Session isn't locked -----
|
||||||
|
|
||||||
|
// If this is a notification about a multimedia message from a contact we know about..
|
||||||
} else if (record.isMms() && !((MmsMessageRecord) record).getSharedContacts().isEmpty()) {
|
} else if (record.isMms() && !((MmsMessageRecord) record).getSharedContacts().isEmpty()) {
|
||||||
Contact contact = ((MmsMessageRecord) record).getSharedContacts().get(0);
|
Contact contact = ((MmsMessageRecord) record).getSharedContacts().get(0);
|
||||||
body = ContactUtil.getStringSummary(context, contact);
|
body = ContactUtil.getStringSummary(context, contact);
|
||||||
|
|
||||||
|
// If this is a notification about a multimedia message which contains no text but DOES contain a slide deck with at least one slide..
|
||||||
} else if (record.isMms() && TextUtils.isEmpty(body) && !((MmsMessageRecord) record).getSlideDeck().getSlides().isEmpty()) {
|
} else if (record.isMms() && TextUtils.isEmpty(body) && !((MmsMessageRecord) record).getSlideDeck().getSlides().isEmpty()) {
|
||||||
slideDeck = ((MediaMmsMessageRecord)record).getSlideDeck();
|
slideDeck = ((MediaMmsMessageRecord)record).getSlideDeck();
|
||||||
body = SpanUtil.italic(slideDeck.getBody());
|
body = SpanUtil.italic(slideDeck.getBody());
|
||||||
|
|
||||||
|
// If this is a notification about a multimedia message, but it's not ITSELF a multimedia notification AND it contains a slide deck with at least one slide..
|
||||||
} else if (record.isMms() && !record.isMmsNotification() && !((MmsMessageRecord) record).getSlideDeck().getSlides().isEmpty()) {
|
} else if (record.isMms() && !record.isMmsNotification() && !((MmsMessageRecord) record).getSlideDeck().getSlides().isEmpty()) {
|
||||||
slideDeck = ((MediaMmsMessageRecord)record).getSlideDeck();
|
slideDeck = ((MediaMmsMessageRecord)record).getSlideDeck();
|
||||||
String message = slideDeck.getBody() + ": " + record.getBody();
|
String message = slideDeck.getBody() + ": " + record.getBody();
|
||||||
int italicLength = message.length() - body.length();
|
int italicLength = message.length() - body.length();
|
||||||
body = SpanUtil.italic(message, italicLength);
|
body = SpanUtil.italic(message, italicLength);
|
||||||
|
|
||||||
|
// If this is a notification about an invitation to a community..
|
||||||
} else if (record.isOpenGroupInvitation()) {
|
} else if (record.isOpenGroupInvitation()) {
|
||||||
body = SpanUtil.italic(context.getString(R.string.ThreadRecord_open_group_invitation));
|
body = SpanUtil.italic(context.getString(R.string.ThreadRecord_open_group_invitation));
|
||||||
}
|
}
|
||||||
|
|
||||||
String userPublicKey = TextSecurePreferences.getLocalNumber(context);
|
String userPublicKey = TextSecurePreferences.getLocalNumber(context);
|
||||||
String blindedPublicKey = cache.get(threadId);
|
String blindedPublicKey = cache.get(threadId);
|
||||||
if (blindedPublicKey == null) {
|
if (blindedPublicKey == null) {
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
package org.thoughtcrime.securesms.notifications;
|
package org.thoughtcrime.securesms.notifications;
|
||||||
|
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.ApplicationContext;
|
import org.thoughtcrime.securesms.ApplicationContext;
|
||||||
import org.thoughtcrime.securesms.dependencies.DatabaseComponent;
|
import org.thoughtcrime.securesms.dependencies.DatabaseComponent;
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ import androidx.lifecycle.lifecycleScope
|
|||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.session.libsession.utilities.TextSecurePreferences
|
import org.session.libsession.utilities.TextSecurePreferences
|
||||||
import org.thoughtcrime.securesms.ApplicationContext
|
|
||||||
import org.thoughtcrime.securesms.BaseActionBarActivity
|
import org.thoughtcrime.securesms.BaseActionBarActivity
|
||||||
import org.thoughtcrime.securesms.dependencies.ConfigFactory
|
import org.thoughtcrime.securesms.dependencies.ConfigFactory
|
||||||
import org.thoughtcrime.securesms.home.startHomeActivity
|
import org.thoughtcrime.securesms.home.startHomeActivity
|
||||||
@ -33,7 +32,7 @@ class LoadingActivity: BaseActionBarActivity() {
|
|||||||
|
|
||||||
when {
|
when {
|
||||||
loadFailed -> startPickDisplayNameActivity(loadFailed = true)
|
loadFailed -> startPickDisplayNameActivity(loadFailed = true)
|
||||||
else -> startHomeActivity()
|
else -> startHomeActivity(isNewAccount = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
finish()
|
finish()
|
||||||
@ -44,8 +43,6 @@ class LoadingActivity: BaseActionBarActivity() {
|
|||||||
|
|
||||||
setUpActionBarSessionLogo()
|
setUpActionBarSessionLogo()
|
||||||
|
|
||||||
ApplicationContext.getInstance(this).newAccount = false
|
|
||||||
|
|
||||||
setComposeContent {
|
setComposeContent {
|
||||||
val progress by viewModel.progress.collectAsState()
|
val progress by viewModel.progress.collectAsState()
|
||||||
LoadingScreen(progress)
|
LoadingScreen(progress)
|
||||||
|
@ -49,7 +49,7 @@ class MessageNotificationsActivity : BaseActionBarActivity() {
|
|||||||
viewModel.events.collect {
|
viewModel.events.collect {
|
||||||
when (it) {
|
when (it) {
|
||||||
Event.Loading -> start<LoadingActivity>()
|
Event.Loading -> start<LoadingActivity>()
|
||||||
Event.OnboardingComplete -> startHomeActivity()
|
Event.OnboardingComplete -> startHomeActivity(isNewAccount = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ class PickDisplayNameActivity : BaseActionBarActivity() {
|
|||||||
viewModel.events.collect {
|
viewModel.events.collect {
|
||||||
when (it) {
|
when (it) {
|
||||||
is Event.CreateAccount -> startMessageNotificationsActivity(it.profileName)
|
is Event.CreateAccount -> startMessageNotificationsActivity(it.profileName)
|
||||||
Event.LoadAccountComplete -> startHomeActivity()
|
Event.LoadAccountComplete -> startHomeActivity(isNewAccount = false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -72,8 +72,6 @@ class PickDisplayNameActivity : BaseActionBarActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun Context.startPickDisplayNameActivity(loadFailed: Boolean = false, flags: Int = 0) {
|
fun Context.startPickDisplayNameActivity(loadFailed: Boolean = false, flags: Int = 0) {
|
||||||
ApplicationContext.getInstance(this).newAccount = !loadFailed
|
|
||||||
|
|
||||||
Intent(this, PickDisplayNameActivity::class.java)
|
Intent(this, PickDisplayNameActivity::class.java)
|
||||||
.apply { putExtra(EXTRA_LOAD_FAILED, loadFailed) }
|
.apply { putExtra(EXTRA_LOAD_FAILED, loadFailed) }
|
||||||
.also { it.flags = flags }
|
.also { it.flags = flags }
|
||||||
|
@ -72,7 +72,7 @@ class QRCodeActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun Tabs(sessionId: String, errors: Flow<String>, onScan: (String) -> Unit) {
|
private fun Tabs(accountId: String, errors: Flow<String>, onScan: (String) -> Unit) {
|
||||||
val pagerState = rememberPagerState { TITLES.size }
|
val pagerState = rememberPagerState { TITLES.size }
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
@ -82,7 +82,7 @@ private fun Tabs(sessionId: String, errors: Flow<String>, onScan: (String) -> Un
|
|||||||
modifier = Modifier.weight(1f)
|
modifier = Modifier.weight(1f)
|
||||||
) { page ->
|
) { page ->
|
||||||
when (TITLES[page]) {
|
when (TITLES[page]) {
|
||||||
R.string.view -> QrPage(sessionId)
|
R.string.view -> QrPage(accountId)
|
||||||
R.string.scan -> MaybeScanQrCode(errors, onScan = onScan)
|
R.string.scan -> MaybeScanQrCode(errors, onScan = onScan)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,9 +35,6 @@ import androidx.core.view.isVisible
|
|||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import java.io.File
|
|
||||||
import java.security.SecureRandom
|
|
||||||
import javax.inject.Inject
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.channels.awaitClose
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
@ -49,7 +46,6 @@ import network.loki.messenger.BuildConfig
|
|||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
import network.loki.messenger.databinding.ActivitySettingsBinding
|
import network.loki.messenger.databinding.ActivitySettingsBinding
|
||||||
import network.loki.messenger.libsession_util.util.UserPic
|
import network.loki.messenger.libsession_util.util.UserPic
|
||||||
import nl.komponents.kovenant.Promise
|
|
||||||
import nl.komponents.kovenant.ui.alwaysUi
|
import nl.komponents.kovenant.ui.alwaysUi
|
||||||
import nl.komponents.kovenant.ui.failUi
|
import nl.komponents.kovenant.ui.failUi
|
||||||
import nl.komponents.kovenant.ui.successUi
|
import nl.komponents.kovenant.ui.successUi
|
||||||
@ -90,8 +86,12 @@ import org.thoughtcrime.securesms.ui.setThemedContent
|
|||||||
import org.thoughtcrime.securesms.util.BitmapDecodingException
|
import org.thoughtcrime.securesms.util.BitmapDecodingException
|
||||||
import org.thoughtcrime.securesms.util.BitmapUtil
|
import org.thoughtcrime.securesms.util.BitmapUtil
|
||||||
import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
|
import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
|
||||||
|
import org.thoughtcrime.securesms.util.NetworkUtils
|
||||||
import org.thoughtcrime.securesms.util.push
|
import org.thoughtcrime.securesms.util.push
|
||||||
import org.thoughtcrime.securesms.util.show
|
import org.thoughtcrime.securesms.util.show
|
||||||
|
import java.io.File
|
||||||
|
import java.security.SecureRandom
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||||
@ -197,7 +197,7 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
try {
|
try {
|
||||||
val profilePictureToBeUploaded = BitmapUtil.createScaledBytes(this@SettingsActivity, AvatarSelection.getResultUri(data), ProfileMediaConstraints()).bitmap
|
val profilePictureToBeUploaded = BitmapUtil.createScaledBytes(this@SettingsActivity, AvatarSelection.getResultUri(data), ProfileMediaConstraints()).bitmap
|
||||||
launch(Dispatchers.Main) {
|
launch(Dispatchers.Main) {
|
||||||
updateProfile(true, profilePictureToBeUploaded)
|
updateProfilePicture(profilePictureToBeUploaded)
|
||||||
}
|
}
|
||||||
} catch (e: BitmapDecodingException) {
|
} catch (e: BitmapDecodingException) {
|
||||||
Log.e(TAG, e)
|
Log.e(TAG, e)
|
||||||
@ -246,57 +246,60 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateProfile(
|
private fun updateDisplayName(displayName: String): Boolean {
|
||||||
isUpdatingProfilePicture: Boolean,
|
|
||||||
profilePicture: ByteArray? = null,
|
|
||||||
displayName: String? = null
|
|
||||||
) {
|
|
||||||
binding.loader.isVisible = true
|
binding.loader.isVisible = true
|
||||||
|
|
||||||
if (displayName != null) {
|
// We'll assume we fail & flip the flag on success
|
||||||
TextSecurePreferences.setProfileName(this, displayName)
|
var updateWasSuccessful = false
|
||||||
configFactory.user?.setName(displayName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bail if we're not updating the profile picture in any way
|
val haveNetworkConnection = NetworkUtils.haveValidNetworkConnection(this@SettingsActivity);
|
||||||
if (!isUpdatingProfilePicture) return
|
if (!haveNetworkConnection) {
|
||||||
|
Log.w(TAG, "Cannot update display name - no network connection.")
|
||||||
val encodedProfileKey = ProfileKeyUtil.generateEncodedProfileKey(this)
|
|
||||||
|
|
||||||
val uploadProfilePicturePromise: Promise<*, Exception>
|
|
||||||
var removingProfilePic = false
|
|
||||||
|
|
||||||
// Adding a new profile picture?
|
|
||||||
if (profilePicture != null) {
|
|
||||||
uploadProfilePicturePromise = ProfilePictureUtilities.upload(profilePicture, encodedProfileKey, this)
|
|
||||||
} else {
|
} else {
|
||||||
// If not then we must be removing the existing one.
|
// if we have a network connection then attempt to update the display name
|
||||||
// Note: To get a promise that will resolve / sync correctly we overwrite the existing profile picture with
|
TextSecurePreferences.setProfileName(this, displayName)
|
||||||
// a 0 byte image.
|
val user = configFactory.user
|
||||||
removingProfilePic = true
|
if (user == null) {
|
||||||
val emptyByteArray = ByteArray(0)
|
Log.w(TAG, "Cannot update display name - missing user details from configFactory.")
|
||||||
uploadProfilePicturePromise = ProfilePictureUtilities.upload(emptyByteArray, encodedProfileKey, this)
|
} else {
|
||||||
|
user.setName(displayName)
|
||||||
|
binding.btnGroupNameDisplay.text = displayName
|
||||||
|
updateWasSuccessful = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the upload picture promise succeeded then we hit this successUi block
|
// Inform the user if we failed to update the display name
|
||||||
uploadProfilePicturePromise.successUi {
|
if (!updateWasSuccessful) {
|
||||||
|
Toast.makeText(this@SettingsActivity, R.string.profileErrorUpdate, Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
|
||||||
// If we successfully removed the profile picture on the network then we can clear the
|
binding.loader.isVisible = false
|
||||||
// local data - otherwise it's weird to fail the online section but it _looks_ like it
|
return updateWasSuccessful
|
||||||
// worked because we cleared the local image (also it denies them the chance to retry
|
}
|
||||||
// removal if we do it locally, and may result in them having a visible profile picture
|
|
||||||
// everywhere EXCEPT on their own device!).
|
// Helper method used by updateProfilePicture and removeProfilePicture to sync it online
|
||||||
if (removingProfilePic) {
|
private fun syncProfilePicture(profilePicture: ByteArray, onFail: () -> Unit) {
|
||||||
|
binding.loader.isVisible = true
|
||||||
|
|
||||||
|
// Grab the profile key and kick of the promise to update the profile picture
|
||||||
|
val encodedProfileKey = ProfileKeyUtil.generateEncodedProfileKey(this)
|
||||||
|
val updateProfilePicturePromise = ProfilePictureUtilities.upload(profilePicture, encodedProfileKey, this)
|
||||||
|
|
||||||
|
// If the online portion of the update succeeded then update the local state
|
||||||
|
updateProfilePicturePromise.successUi {
|
||||||
|
|
||||||
|
// When removing the profile picture the supplied ByteArray is empty so we'll clear the local data
|
||||||
|
if (profilePicture.isEmpty()) {
|
||||||
MessagingModuleConfiguration.shared.storage.clearUserPic()
|
MessagingModuleConfiguration.shared.storage.clearUserPic()
|
||||||
}
|
}
|
||||||
|
|
||||||
val userConfig = configFactory.user
|
val userConfig = configFactory.user
|
||||||
AvatarHelper.setAvatar(this, Address.fromSerialized(TextSecurePreferences.getLocalNumber(this)!!), profilePicture)
|
AvatarHelper.setAvatar(this, Address.fromSerialized(TextSecurePreferences.getLocalNumber(this)!!), profilePicture)
|
||||||
prefs.setProfileAvatarId(profilePicture?.let { SecureRandom().nextInt() } ?: 0 )
|
prefs.setProfileAvatarId(SecureRandom().nextInt() )
|
||||||
|
|
||||||
ProfileKeyUtil.setEncodedProfileKey(this, encodedProfileKey)
|
ProfileKeyUtil.setEncodedProfileKey(this, encodedProfileKey)
|
||||||
// new config
|
|
||||||
val url = TextSecurePreferences.getProfilePictureURL(this)
|
// Attempt to grab the details we require to update the profile picture
|
||||||
|
val url = prefs.getProfilePictureURL()
|
||||||
val profileKey = ProfileKeyUtil.getProfileKey(this)
|
val profileKey = ProfileKeyUtil.getProfileKey(this)
|
||||||
|
|
||||||
// If we have a URL and a profile key then set the user's profile picture
|
// If we have a URL and a profile key then set the user's profile picture
|
||||||
@ -309,30 +312,52 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(this@SettingsActivity)
|
ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(this@SettingsActivity)
|
||||||
|
|
||||||
|
// Update our visuals
|
||||||
|
binding.profilePictureView.recycle()
|
||||||
|
binding.profilePictureView.update()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Or if the promise failed to upload the new profile picture then we hit this failUi block
|
// If the sync failed then inform the user
|
||||||
uploadProfilePicturePromise.failUi {
|
updateProfilePicturePromise.failUi { onFail() }
|
||||||
if (removingProfilePic) {
|
|
||||||
Log.e(TAG, "Failed to remove profile picture")
|
// Finally, remove the loader animation after we've waited for the attempt to succeed or fail
|
||||||
Toast.makeText(this@SettingsActivity, R.string.profileDisplayPictureRemoveError, Toast.LENGTH_LONG).show()
|
updateProfilePicturePromise.alwaysUi { binding.loader.isVisible = false }
|
||||||
} else {
|
}
|
||||||
Log.e(TAG, "Failed to upload profile picture")
|
|
||||||
Toast.makeText(this@SettingsActivity, R.string.profileErrorUpdate, Toast.LENGTH_LONG).show()
|
private fun updateProfilePicture(profilePicture: ByteArray) {
|
||||||
}
|
|
||||||
|
val haveNetworkConnection = NetworkUtils.haveValidNetworkConnection(this@SettingsActivity);
|
||||||
|
if (!haveNetworkConnection) {
|
||||||
|
Log.w(TAG, "Cannot update profile picture - no network connection.")
|
||||||
|
Toast.makeText(this@SettingsActivity, R.string.profileErrorUpdate, Toast.LENGTH_LONG).show()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, regardless of whether the promise succeeded or failed, we always hit this `alwaysUi` block
|
val onFail: () -> Unit = {
|
||||||
uploadProfilePicturePromise.alwaysUi {
|
Log.e(TAG, "Sync failed when uploading profile picture.")
|
||||||
if (displayName != null) {
|
Toast.makeText(this@SettingsActivity, R.string.profileErrorUpdate, Toast.LENGTH_LONG).show()
|
||||||
binding.btnGroupNameDisplay.text = displayName
|
|
||||||
}
|
|
||||||
if (isUpdatingProfilePicture) {
|
|
||||||
binding.profilePictureView.recycle() // Clear the cached image before updating
|
|
||||||
binding.profilePictureView.update()
|
|
||||||
}
|
|
||||||
binding.loader.isVisible = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
syncProfilePicture(profilePicture, onFail)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun removeProfilePicture() {
|
||||||
|
|
||||||
|
val haveNetworkConnection = NetworkUtils.haveValidNetworkConnection(this@SettingsActivity);
|
||||||
|
if (!haveNetworkConnection) {
|
||||||
|
Log.w(TAG, "Cannot remove profile picture - no network connection.")
|
||||||
|
Toast.makeText(this@SettingsActivity, R.string.profileDisplayPictureRemoveError, Toast.LENGTH_LONG).show()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val onFail: () -> Unit = {
|
||||||
|
Log.e(TAG, "Sync failed when removing profile picture.")
|
||||||
|
Toast.makeText(this@SettingsActivity, R.string.profileDisplayPictureRemoveError, Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
val emptyProfilePicture = ByteArray(0)
|
||||||
|
syncProfilePicture(emptyProfilePicture, onFail)
|
||||||
}
|
}
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
@ -351,8 +376,7 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
Toast.makeText(this, R.string.activity_settings_display_name_too_long_error, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, R.string.activity_settings_display_name_too_long_error, Toast.LENGTH_SHORT).show()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
updateProfile(false, displayName = displayName)
|
return updateDisplayName(displayName)
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showEditProfilePictureUI() {
|
private fun showEditProfilePictureUI() {
|
||||||
@ -361,7 +385,7 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
view(R.layout.dialog_change_avatar)
|
view(R.layout.dialog_change_avatar)
|
||||||
button(R.string.activity_settings_upload) { startAvatarSelection() }
|
button(R.string.activity_settings_upload) { startAvatarSelection() }
|
||||||
if (prefs.getProfileAvatarId() != 0) {
|
if (prefs.getProfileAvatarId() != 0) {
|
||||||
button(R.string.activity_settings_remove) { removeAvatar() }
|
button(R.string.activity_settings_remove) { removeProfilePicture() }
|
||||||
}
|
}
|
||||||
cancelButton()
|
cancelButton()
|
||||||
}.apply {
|
}.apply {
|
||||||
@ -379,10 +403,6 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeAvatar() {
|
|
||||||
updateProfile(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun startAvatarSelection() {
|
private fun startAvatarSelection() {
|
||||||
// Ask for an optional camera permission.
|
// Ask for an optional camera permission.
|
||||||
Permissions.with(this)
|
Permissions.with(this)
|
||||||
|
@ -293,7 +293,7 @@ class DefaultConversationRepository @Inject constructor(
|
|||||||
|
|
||||||
override suspend fun banAndDeleteAll(threadId: Long, recipient: Recipient): ResultOf<Unit> =
|
override suspend fun banAndDeleteAll(threadId: Long, recipient: Recipient): ResultOf<Unit> =
|
||||||
suspendCoroutine { continuation ->
|
suspendCoroutine { continuation ->
|
||||||
// Note: This sessionId could be the blinded Id
|
// Note: This accountId could be the blinded Id
|
||||||
val accountID = recipient.address.toString()
|
val accountID = recipient.address.toString()
|
||||||
val openGroup = lokiThreadDb.getOpenGroupChat(threadId)!!
|
val openGroup = lokiThreadDb.getOpenGroupChat(threadId)!!
|
||||||
|
|
||||||
|
@ -92,8 +92,8 @@ class ProfileManager(private val context: Context, private val configFactory: Co
|
|||||||
override fun contactUpdatedInternal(contact: Contact): String? {
|
override fun contactUpdatedInternal(contact: Contact): String? {
|
||||||
val contactConfig = configFactory.contacts ?: return null
|
val contactConfig = configFactory.contacts ?: return null
|
||||||
if (contact.accountID == TextSecurePreferences.getLocalNumber(context)) return null
|
if (contact.accountID == TextSecurePreferences.getLocalNumber(context)) return null
|
||||||
val sessionId = AccountId(contact.accountID)
|
val accountId = AccountId(contact.accountID)
|
||||||
if (sessionId.prefix != IdPrefix.STANDARD) return null // only internally store standard session IDs
|
if (accountId.prefix != IdPrefix.STANDARD) return null // only internally store standard account IDs
|
||||||
contactConfig.upsertContact(contact.accountID) {
|
contactConfig.upsertContact(contact.accountID) {
|
||||||
this.name = contact.name.orEmpty()
|
this.name = contact.name.orEmpty()
|
||||||
this.nickname = contact.nickname.orEmpty()
|
this.nickname = contact.nickname.orEmpty()
|
||||||
|
@ -205,7 +205,7 @@ object ConfigurationMessageUtilities {
|
|||||||
val admins = group.admins.map { it.serialize() to true }.toMap()
|
val admins = group.admins.map { it.serialize() to true }.toMap()
|
||||||
val members = group.members.filterNot { it.serialize() !in admins.keys }.map { it.serialize() to false }.toMap()
|
val members = group.members.filterNot { it.serialize() !in admins.keys }.map { it.serialize() to false }.toMap()
|
||||||
GroupInfo.LegacyGroupInfo(
|
GroupInfo.LegacyGroupInfo(
|
||||||
sessionId = groupPublicKey,
|
accountId = groupPublicKey,
|
||||||
name = group.title,
|
name = group.title,
|
||||||
members = admins + members,
|
members = admins + members,
|
||||||
priority = if (isPinned) ConfigBase.PRIORITY_PINNED else ConfigBase.PRIORITY_VISIBLE,
|
priority = if (isPinned) ConfigBase.PRIORITY_PINNED else ConfigBase.PRIORITY_VISIBLE,
|
||||||
|
@ -186,9 +186,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">أختر الكل</string>
|
<string name="MediaOverviewActivity_Select_all">أختر الكل</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">جارٍ جمع المرفقات...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">جارٍ جمع المرفقات...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">رسالة وسائط متعددة</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">تنزيل رسالة الوسائط المتعددة</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">خطأ في تنزيل رسالة الوسائط المتعددة، انقر لاعادة المحاولة</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">إرسال إلى %s</string>
|
<string name="MediaPickerActivity_send_to">إرسال إلى %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -186,9 +186,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">أختر الكل</string>
|
<string name="MediaOverviewActivity_Select_all">أختر الكل</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">جارٍ جمع المرفقات...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">جارٍ جمع المرفقات...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">رسالة وسائط متعددة</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">تنزيل رسالة الوسائط المتعددة</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">خطأ في تنزيل رسالة الوسائط المتعددة، انقر لاعادة المحاولة</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">إرسال إلى %s</string>
|
<string name="MediaPickerActivity_send_to">إرسال إلى %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -150,9 +150,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Hamısını seç</string>
|
<string name="MediaOverviewActivity_Select_all">Hamısını seç</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Qoşmalar yığılır...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Qoşmalar yığılır...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Multimedia mesajı</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">MMS mesaj endirilir</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">MMS mesajı endirmə xətası, yenidən sınamaq üçün toxunun</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">%s - göndər</string>
|
<string name="MediaPickerActivity_send_to">%s - göndər</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -150,9 +150,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Hamısını seç</string>
|
<string name="MediaOverviewActivity_Select_all">Hamısını seç</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Qoşmalar yığılır...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Qoşmalar yığılır...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Multimedia mesajı</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">MMS mesaj endirilir</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">MMS mesajı endirmə xətası, yenidən sınamaq üçün toxunun</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">%s - göndər</string>
|
<string name="MediaPickerActivity_send_to">%s - göndər</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -96,9 +96,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Pilih semua</string>
|
<string name="MediaOverviewActivity_Select_all">Pilih semua</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Mengumpulkan lampiran...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Mengumpulkan lampiran...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Pesan multimedia</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Mengunduh pesan MMS.</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Gagal saat mengunduh pesan MMS, ketuk untuk mencoba lagi</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Kirim ke %s</string>
|
<string name="MediaPickerActivity_send_to">Kirim ke %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -96,9 +96,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Pilih semua</string>
|
<string name="MediaOverviewActivity_Select_all">Pilih semua</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Mengumpulkan lampiran...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Mengumpulkan lampiran...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Pesan multimedia</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Mengunduh pesan MMS.</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Gagal saat mengunduh pesan MMS, ketuk untuk mencoba lagi</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Kirim ke %s</string>
|
<string name="MediaPickerActivity_send_to">Kirim ke %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -142,9 +142,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Избери всичко</string>
|
<string name="MediaOverviewActivity_Select_all">Избери всичко</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Събиране на прикачени файлове...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Събиране на прикачени файлове...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Мултимедийно съобщение</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Изтегляне на MMS съобщение</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Грешка при изтегляне на MMS съобщение, натиснете за да опитате повторно</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Изпрати на %s</string>
|
<string name="MediaPickerActivity_send_to">Изпрати на %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -142,9 +142,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Избери всичко</string>
|
<string name="MediaOverviewActivity_Select_all">Избери всичко</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Събиране на прикачени файлове...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Събиране на прикачени файлове...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Мултимедийно съобщение</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Изтегляне на MMS съобщение</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Грешка при изтегляне на MMS съобщение, натиснете за да опитате повторно</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Изпрати на %s</string>
|
<string name="MediaPickerActivity_send_to">Изпрати на %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -147,9 +147,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Selecciona-ho tot</string>
|
<string name="MediaOverviewActivity_Select_all">Selecciona-ho tot</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">S\'estan adjuntant els fitxers...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">S\'estan adjuntant els fitxers...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Missatge multimèdia</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">S\'està baixant el missatge MMS</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">S\'ha produït un error en baixar el missatge MMS. Toqueu per tornar a intentar-ho</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Envia-ho a %s</string>
|
<string name="MediaPickerActivity_send_to">Envia-ho a %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -147,9 +147,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Selecciona-ho tot</string>
|
<string name="MediaOverviewActivity_Select_all">Selecciona-ho tot</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">S\'estan adjuntant els fitxers...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">S\'estan adjuntant els fitxers...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Missatge multimèdia</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">S\'està baixant el missatge MMS</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">S\'ha produït un error en baixar el missatge MMS. Toqueu per tornar a intentar-ho</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Envia-ho a %s</string>
|
<string name="MediaPickerActivity_send_to">Envia-ho a %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -168,9 +168,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Označit vše</string>
|
<string name="MediaOverviewActivity_Select_all">Označit vše</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Shromažďuji přílohy...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Shromažďuji přílohy...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Multimediální zpráva</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Stahuji MMS zprávu</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Chyba při stahování MMS zprávy, ťukněte pro opakování</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Poslat %s</string>
|
<string name="MediaPickerActivity_send_to">Poslat %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -168,9 +168,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Označit vše</string>
|
<string name="MediaOverviewActivity_Select_all">Označit vše</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Shromažďuji přílohy...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Shromažďuji přílohy...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Multimediální zpráva</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Stahuji MMS zprávu</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Chyba při stahování MMS zprávy, ťukněte pro opakování</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Poslat %s</string>
|
<string name="MediaPickerActivity_send_to">Poslat %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -172,9 +172,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Dewis popeth</string>
|
<string name="MediaOverviewActivity_Select_all">Dewis popeth</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Casglu atodiadau...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Casglu atodiadau...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Neges amlgyfrwng</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Llwytho i lawr neges MMS</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Gwall wrth lawrlwytho neges MMS, tapio i geisio eto</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Anfon i %s</string>
|
<string name="MediaPickerActivity_send_to">Anfon i %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -172,9 +172,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Dewis popeth</string>
|
<string name="MediaOverviewActivity_Select_all">Dewis popeth</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Casglu atodiadau...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Casglu atodiadau...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Neges amlgyfrwng</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Llwytho i lawr neges MMS</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Gwall wrth lawrlwytho neges MMS, tapio i geisio eto</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Anfon i %s</string>
|
<string name="MediaPickerActivity_send_to">Anfon i %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -150,9 +150,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Vælg alle</string>
|
<string name="MediaOverviewActivity_Select_all">Vælg alle</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Samler vedhæftninger...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Samler vedhæftninger...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Multimedie besked</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Downloader MMS...</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">MMS besked kunne ikke downloades, tap for at prøve igen</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Send til %s</string>
|
<string name="MediaPickerActivity_send_to">Send til %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -150,9 +150,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Vælg alle</string>
|
<string name="MediaOverviewActivity_Select_all">Vælg alle</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Samler vedhæftninger...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Samler vedhæftninger...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Multimedie besked</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Downloader MMS...</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">MMS besked kunne ikke downloades, tap for at prøve igen</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Send til %s</string>
|
<string name="MediaPickerActivity_send_to">Send til %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -150,9 +150,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Alle auswählen</string>
|
<string name="MediaOverviewActivity_Select_all">Alle auswählen</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Anhänge werden gesammelt …</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Anhänge werden gesammelt …</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">MMS</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">MMS wird heruntergeladen …</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Fehler beim Herunterladen der MMS. Für erneuten Versuch antippen.</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">An %s senden</string>
|
<string name="MediaPickerActivity_send_to">An %s senden</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
@ -569,7 +566,7 @@
|
|||||||
<string name="activity_create_private_chat_scan_qr_code_explanation">Scannen Sie den QR-Code eines Benutzers, um eine Session zu starten. QR-Codes finden Sie, indem Sie in den Einstellungen auf das QR-Code-Symbol tippen.</string>
|
<string name="activity_create_private_chat_scan_qr_code_explanation">Scannen Sie den QR-Code eines Benutzers, um eine Session zu starten. QR-Codes finden Sie, indem Sie in den Einstellungen auf das QR-Code-Symbol tippen.</string>
|
||||||
<string name="fragment_enter_public_key_edit_text_hint">Sitzungs-ID oder ONS-Name eingeben</string>
|
<string name="fragment_enter_public_key_edit_text_hint">Sitzungs-ID oder ONS-Name eingeben</string>
|
||||||
<string name="fragment_enter_public_key_explanation">Benutzer können ihre Account ID freigeben, indem sie in ihren Einstellungen auf \"Account ID freigeben\" tippen oder ihren QR-Code freigeben.</string>
|
<string name="fragment_enter_public_key_explanation">Benutzer können ihre Account ID freigeben, indem sie in ihren Einstellungen auf \"Account ID freigeben\" tippen oder ihren QR-Code freigeben.</string>
|
||||||
<string name="fragment_enter_public_key_error_message">Bitte überprüfe die Session-ID oder den ONS-Namen und versuche es erneut.</string>
|
<string name="fragment_enter_public_key_error_message">Bitte überprüfe die Account-ID oder den ONS-Namen und versuche es erneut.</string>
|
||||||
<string name="fragment_scan_qr_code_camera_access_explanation">Session benötigt Kamerazugriff, um die QR-Codes scannen zu können.</string>
|
<string name="fragment_scan_qr_code_camera_access_explanation">Session benötigt Kamerazugriff, um die QR-Codes scannen zu können.</string>
|
||||||
<string name="fragment_scan_qr_code_grant_camera_access_button_title">Kamerazugriff gewähren</string>
|
<string name="fragment_scan_qr_code_grant_camera_access_button_title">Kamerazugriff gewähren</string>
|
||||||
<string name="activity_create_closed_group_title">Neue geschlossene Gruppe</string>
|
<string name="activity_create_closed_group_title">Neue geschlossene Gruppe</string>
|
||||||
@ -641,7 +638,7 @@
|
|||||||
<string name="dialog_ui_mode_option_day">Tag</string>
|
<string name="dialog_ui_mode_option_day">Tag</string>
|
||||||
<string name="dialog_ui_mode_option_night">Nacht</string>
|
<string name="dialog_ui_mode_option_night">Nacht</string>
|
||||||
<string name="dialog_ui_mode_option_system_default">Systemstandard</string>
|
<string name="dialog_ui_mode_option_system_default">Systemstandard</string>
|
||||||
<string name="activity_conversation_menu_copy_account_id">Session-ID kopieren</string>
|
<string name="activity_conversation_menu_copy_account_id">Account-ID kopieren</string>
|
||||||
<string name="attachment">Anhang</string>
|
<string name="attachment">Anhang</string>
|
||||||
<string name="attachment_type_voice_message">Sprachnachricht</string>
|
<string name="attachment_type_voice_message">Sprachnachricht</string>
|
||||||
<string name="details">Details</string>
|
<string name="details">Details</string>
|
||||||
|
@ -150,9 +150,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Alle auswählen</string>
|
<string name="MediaOverviewActivity_Select_all">Alle auswählen</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Anhänge werden gesammelt …</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Anhänge werden gesammelt …</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">MMS</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">MMS wird heruntergeladen …</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Fehler beim Herunterladen der MMS. Für erneuten Versuch antippen.</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">An %s senden</string>
|
<string name="MediaPickerActivity_send_to">An %s senden</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
@ -569,7 +566,7 @@
|
|||||||
<string name="activity_create_private_chat_scan_qr_code_explanation">Scannen Sie den QR-Code eines Benutzers, um eine Session zu starten. QR-Codes finden Sie, indem Sie in den Einstellungen auf das QR-Code-Symbol tippen.</string>
|
<string name="activity_create_private_chat_scan_qr_code_explanation">Scannen Sie den QR-Code eines Benutzers, um eine Session zu starten. QR-Codes finden Sie, indem Sie in den Einstellungen auf das QR-Code-Symbol tippen.</string>
|
||||||
<string name="fragment_enter_public_key_edit_text_hint">Sitzungs-ID oder ONS-Name eingeben</string>
|
<string name="fragment_enter_public_key_edit_text_hint">Sitzungs-ID oder ONS-Name eingeben</string>
|
||||||
<string name="fragment_enter_public_key_explanation">Benutzer können ihre Account ID freigeben, indem sie in ihren Einstellungen auf \"Account ID freigeben\" tippen oder ihren QR-Code freigeben.</string>
|
<string name="fragment_enter_public_key_explanation">Benutzer können ihre Account ID freigeben, indem sie in ihren Einstellungen auf \"Account ID freigeben\" tippen oder ihren QR-Code freigeben.</string>
|
||||||
<string name="fragment_enter_public_key_error_message">Bitte überprüfe die Session-ID oder den ONS-Namen und versuche es erneut.</string>
|
<string name="fragment_enter_public_key_error_message">Bitte überprüfe die Account-ID oder den ONS-Namen und versuche es erneut.</string>
|
||||||
<string name="fragment_scan_qr_code_camera_access_explanation">Session benötigt Kamerazugriff, um die QR-Codes scannen zu können.</string>
|
<string name="fragment_scan_qr_code_camera_access_explanation">Session benötigt Kamerazugriff, um die QR-Codes scannen zu können.</string>
|
||||||
<string name="fragment_scan_qr_code_grant_camera_access_button_title">Kamerazugriff gewähren</string>
|
<string name="fragment_scan_qr_code_grant_camera_access_button_title">Kamerazugriff gewähren</string>
|
||||||
<string name="activity_create_closed_group_title">Neue geschlossene Gruppe</string>
|
<string name="activity_create_closed_group_title">Neue geschlossene Gruppe</string>
|
||||||
@ -641,7 +638,7 @@
|
|||||||
<string name="dialog_ui_mode_option_day">Tag</string>
|
<string name="dialog_ui_mode_option_day">Tag</string>
|
||||||
<string name="dialog_ui_mode_option_night">Nacht</string>
|
<string name="dialog_ui_mode_option_night">Nacht</string>
|
||||||
<string name="dialog_ui_mode_option_system_default">Systemstandard</string>
|
<string name="dialog_ui_mode_option_system_default">Systemstandard</string>
|
||||||
<string name="activity_conversation_menu_copy_account_id">Session-ID kopieren</string>
|
<string name="activity_conversation_menu_copy_account_id">Account-ID kopieren</string>
|
||||||
<string name="attachment">Anhang</string>
|
<string name="attachment">Anhang</string>
|
||||||
<string name="attachment_type_voice_message">Sprachnachricht</string>
|
<string name="attachment_type_voice_message">Sprachnachricht</string>
|
||||||
<string name="details">Details</string>
|
<string name="details">Details</string>
|
||||||
|
@ -150,9 +150,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Επιλογή όλων</string>
|
<string name="MediaOverviewActivity_Select_all">Επιλογή όλων</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Τα συνημμένα συλλέγονται...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Τα συνημμένα συλλέγονται...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Μήνυμα πολυμέσων</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Το μήνυμα MMS λαμβάνεται</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Πρόβλημα κατά τη λήψη μηνύματος MMS, πατήστε για να ξαναδοκιμάσουμε</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Αποστολή σε %s</string>
|
<string name="MediaPickerActivity_send_to">Αποστολή σε %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -150,9 +150,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Επιλογή όλων</string>
|
<string name="MediaOverviewActivity_Select_all">Επιλογή όλων</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Τα συνημμένα συλλέγονται...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Τα συνημμένα συλλέγονται...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Μήνυμα πολυμέσων</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Το μήνυμα MMS λαμβάνεται</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Πρόβλημα κατά τη λήψη μηνύματος MMS, πατήστε για να ξαναδοκιμάσουμε</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Αποστολή σε %s</string>
|
<string name="MediaPickerActivity_send_to">Αποστολή σε %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -150,9 +150,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Elekti ĉiujn</string>
|
<string name="MediaOverviewActivity_Select_all">Elekti ĉiujn</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Kolekto de kunsendaĵoj...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Kolekto de kunsendaĵoj...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Aŭdvida mesaĝo</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Elŝutante MMS-mesaĝon</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Eraro dum elŝuto de MMS-mesaĝo, tuŝetu por reprovi</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Sendi al %s</string>
|
<string name="MediaPickerActivity_send_to">Sendi al %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -150,9 +150,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Elekti ĉiujn</string>
|
<string name="MediaOverviewActivity_Select_all">Elekti ĉiujn</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Kolekto de kunsendaĵoj...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Kolekto de kunsendaĵoj...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Aŭdvida mesaĝo</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Elŝutante MMS-mesaĝon</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Eraro dum elŝuto de MMS-mesaĝo, tuŝetu por reprovi</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Sendi al %s</string>
|
<string name="MediaPickerActivity_send_to">Sendi al %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -150,9 +150,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Seleccionar todo</string>
|
<string name="MediaOverviewActivity_Select_all">Seleccionar todo</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Recopilando adjuntos ...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Recopilando adjuntos ...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Mensaje multimedia</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Descargando mensaje MMS</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Fallo al descargar mensaje MMS, toca para reintentar</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Enviar a %s</string>
|
<string name="MediaPickerActivity_send_to">Enviar a %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -150,9 +150,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Seleccionar todo</string>
|
<string name="MediaOverviewActivity_Select_all">Seleccionar todo</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Recopilando adjuntos ...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Recopilando adjuntos ...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Mensaje multimedia</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Descargando mensaje MMS</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Fallo al descargar mensaje MMS, toca para reintentar</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Enviar a %s</string>
|
<string name="MediaPickerActivity_send_to">Enviar a %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -134,9 +134,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Vali kõik</string>
|
<string name="MediaOverviewActivity_Select_all">Vali kõik</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Kogun manuseid...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Kogun manuseid...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Multimeediasõnum</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Laadin alla MMS-sõnumit</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">MMS-sõnumi allalaadimisel tekkis viga, koputa uuesti proovimiseks</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Saada kohta %s</string>
|
<string name="MediaPickerActivity_send_to">Saada kohta %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -134,9 +134,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Vali kõik</string>
|
<string name="MediaOverviewActivity_Select_all">Vali kõik</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Kogun manuseid...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Kogun manuseid...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Multimeediasõnum</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Laadin alla MMS-sõnumit</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">MMS-sõnumi allalaadimisel tekkis viga, koputa uuesti proovimiseks</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Saada kohta %s</string>
|
<string name="MediaPickerActivity_send_to">Saada kohta %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -156,9 +156,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">انتخاب همه</string>
|
<string name="MediaOverviewActivity_Select_all">انتخاب همه</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">در حال جمعآوری پیوستها...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">در حال جمعآوری پیوستها...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">پیام های چند رسانه ای</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">در حال بارگیری پیام چندرسانهای...</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">بروز مشکل در دانلود پیام MMS، جهت تلاش دوباره تپ کنید</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">ارسال به %s</string>
|
<string name="MediaPickerActivity_send_to">ارسال به %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -150,9 +150,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">انتخاب همه</string>
|
<string name="MediaOverviewActivity_Select_all">انتخاب همه</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">در حال جمعآوری پیوستها...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">در حال جمعآوری پیوستها...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">پیام های چند رسانه ای</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">در حال بارگیری پیام چندرسانهای...</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">بروز مشکل در دانلود پیام MMS، جهت تلاش دوباره تپ کنید</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">ارسال به %s</string>
|
<string name="MediaPickerActivity_send_to">ارسال به %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -150,9 +150,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Valitse kaikki</string>
|
<string name="MediaOverviewActivity_Select_all">Valitse kaikki</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Kerätään liitetiedostoja...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Kerätään liitetiedostoja...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Multimediaviesti</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Ladataan MMS-viestiä</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Virhe ladattaessa MMS-viestiä. Yritä uudelleen napauttamalla.</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Lähetä yhteystiedolle %s</string>
|
<string name="MediaPickerActivity_send_to">Lähetä yhteystiedolle %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -150,9 +150,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Valitse kaikki</string>
|
<string name="MediaOverviewActivity_Select_all">Valitse kaikki</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Kerätään liitetiedostoja...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Kerätään liitetiedostoja...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Multimediaviesti</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Ladataan MMS-viestiä</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Virhe ladattaessa MMS-viestiä. Yritä uudelleen napauttamalla.</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Lähetä yhteystiedolle %s</string>
|
<string name="MediaPickerActivity_send_to">Lähetä yhteystiedolle %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -157,9 +157,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Tout sélectionner</string>
|
<string name="MediaOverviewActivity_Select_all">Tout sélectionner</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Récupération des pièces jointes…</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Récupération des pièces jointes…</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Message multimédia</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Téléchargement du message multimédia</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Erreur de téléchargement du message multimédia. Touchez pour ressayer</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Envoyer à %s</string>
|
<string name="MediaPickerActivity_send_to">Envoyer à %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -157,9 +157,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Tout sélectionner</string>
|
<string name="MediaOverviewActivity_Select_all">Tout sélectionner</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Récupération des pièces jointes…</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Récupération des pièces jointes…</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Message multimédia</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Téléchargement du message multimédia</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Erreur de téléchargement du message multimédia. Touchez pour ressayer</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Envoyer à %s</string>
|
<string name="MediaPickerActivity_send_to">Envoyer à %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -149,9 +149,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Seleccionar todo</string>
|
<string name="MediaOverviewActivity_Select_all">Seleccionar todo</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Recompilando anexos...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Recompilando anexos...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Mensaxe multimedia</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Descargando mensaxe MMS</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Erro ao descargar a mensaxe MMS, toca para volver tentar</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Enviar a %s</string>
|
<string name="MediaPickerActivity_send_to">Enviar a %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -149,9 +149,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Seleccionar todo</string>
|
<string name="MediaOverviewActivity_Select_all">Seleccionar todo</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Recompilando anexos...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Recompilando anexos...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Mensaxe multimedia</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Descargando mensaxe MMS</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Erro ao descargar a mensaxe MMS, toca para volver tentar</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Enviar a %s</string>
|
<string name="MediaPickerActivity_send_to">Enviar a %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -134,9 +134,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Gişan bibijêre</string>
|
<string name="MediaOverviewActivity_Select_all">Gişan bibijêre</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">...Servehî tên berhevkirin</string>
|
<string name="MediaOverviewActivity_collecting_attachments">...Servehî tên berhevkirin</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Peyama multîmedyayê</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Peyama MMS tê daxistin</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Peyama MMSê nehate daxistin, ji bo dîsa hewldanê bitepîne</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Ji %s re bişîne</string>
|
<string name="MediaPickerActivity_send_to">Ji %s re bişîne</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -134,9 +134,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Gişan bibijêre</string>
|
<string name="MediaOverviewActivity_Select_all">Gişan bibijêre</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">...Servehî tên berhevkirin</string>
|
<string name="MediaOverviewActivity_collecting_attachments">...Servehî tên berhevkirin</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Peyama multîmedyayê</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Peyama MMS tê daxistin</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Peyama MMSê nehate daxistin, ji bo dîsa hewldanê bitepîne</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Ji %s re bişîne</string>
|
<string name="MediaPickerActivity_send_to">Ji %s re bişîne</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -150,9 +150,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">सभी को चुन लो स`</string>
|
<string name="MediaOverviewActivity_Select_all">सभी को चुन लो स`</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">अटैचमेंट्स इकट्ठे कर रहे हैं...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">अटैचमेंट्स इकट्ठे कर रहे हैं...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">मल्टीमीडिया संदेश</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">एमएमएस संदेश डाउनलोड किया जा रहा है</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">एमएमएस संदेश डाउनलोड करने में त्रुटि, पुनः प्रयास करने के लिए टैप करें</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">%s को भेजें</string>
|
<string name="MediaPickerActivity_send_to">%s को भेजें</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -150,9 +150,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">सभी को चुन लो स`</string>
|
<string name="MediaOverviewActivity_Select_all">सभी को चुन लो स`</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">अटैचमेंट्स इकट्ठे कर रहे हैं...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">अटैचमेंट्स इकट्ठे कर रहे हैं...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">मल्टीमीडिया संदेश</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">एमएमएस संदेश डाउनलोड किया जा रहा है</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">एमएमएस संदेश डाउनलोड करने में त्रुटि, पुनः प्रयास करने के लिए टैप करें</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">%s को भेजें</string>
|
<string name="MediaPickerActivity_send_to">%s को भेजें</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -151,9 +151,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Összes kiválasztása</string>
|
<string name="MediaOverviewActivity_Select_all">Összes kiválasztása</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Mellékletek összegyűjtése...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Mellékletek összegyűjtése...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Multimédia üzenet</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">MMS üzenet letöltése</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Hiba történt az MMS üzenet letöltése során, koppints az újrapróbálkozáshoz</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Küldés neki: %s</string>
|
<string name="MediaPickerActivity_send_to">Küldés neki: %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -151,9 +151,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Összes kiválasztása</string>
|
<string name="MediaOverviewActivity_Select_all">Összes kiválasztása</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Mellékletek összegyűjtése...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Mellékletek összegyűjtése...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Multimédia üzenet</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">MMS üzenet letöltése</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Hiba történt az MMS üzenet letöltése során, koppints az újrapróbálkozáshoz</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Küldés neki: %s</string>
|
<string name="MediaPickerActivity_send_to">Küldés neki: %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -155,9 +155,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Ընտրել բոլորը</string>
|
<string name="MediaOverviewActivity_Select_all">Ընտրել բոլորը</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Կցորդների հավաքում...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Կցորդների հավաքում...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Մուլտիմեդիա հաղորդագրություններ</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Ներբեռնում է MMS հաղորդագրությունը</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Խնդիր առաջացավ MMS հաղորդագրությունը ներբեռնելիս, սեղմեք կրկին փորձելու համար</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Ուղարկել %s֊ին</string>
|
<string name="MediaPickerActivity_send_to">Ուղարկել %s֊ին</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -155,9 +155,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Ընտրել բոլորը</string>
|
<string name="MediaOverviewActivity_Select_all">Ընտրել բոլորը</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Կցորդների հավաքում...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Կցորդների հավաքում...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Մուլտիմեդիա հաղորդագրություններ</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Ներբեռնում է MMS հաղորդագրությունը</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Խնդիր առաջացավ MMS հաղորդագրությունը ներբեռնելիս, սեղմեք կրկին փորձելու համար</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Ուղարկել %s֊ին</string>
|
<string name="MediaPickerActivity_send_to">Ուղարկել %s֊ին</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -126,9 +126,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Pilih semua</string>
|
<string name="MediaOverviewActivity_Select_all">Pilih semua</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Mengumpulkan semua lampiran...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Mengumpulkan semua lampiran...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Pesan Multimedia</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Mengunduh pesan MMS</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Gagal mengunduh pesan MMS, sentuh untuk coba kembali</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Kirim ke %s</string>
|
<string name="MediaPickerActivity_send_to">Kirim ke %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -126,9 +126,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Pilih semua</string>
|
<string name="MediaOverviewActivity_Select_all">Pilih semua</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Mengumpulkan semua lampiran...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Mengumpulkan semua lampiran...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Pesan Multimedia</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Mengunduh pesan MMS</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Gagal mengunduh pesan MMS, sentuh untuk coba kembali</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Kirim ke %s</string>
|
<string name="MediaPickerActivity_send_to">Kirim ke %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -151,9 +151,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Seleziona tutto</string>
|
<string name="MediaOverviewActivity_Select_all">Seleziona tutto</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Recupero allegati...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Recupero allegati...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Messaggio multimediale</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Scarico MMS</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Errore nello scaricare MMS, premi per riprovare</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Invia a %s</string>
|
<string name="MediaPickerActivity_send_to">Invia a %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -151,9 +151,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Seleziona tutto</string>
|
<string name="MediaOverviewActivity_Select_all">Seleziona tutto</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Recupero allegati...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Recupero allegati...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Messaggio multimediale</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Scarico MMS</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Errore nello scaricare MMS, premi per riprovare</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Invia a %s</string>
|
<string name="MediaPickerActivity_send_to">Invia a %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -166,9 +166,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">בחר הכל</string>
|
<string name="MediaOverviewActivity_Select_all">בחר הכל</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">אוסף צרופות...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">אוסף צרופות...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">הודעת מולטימדיה</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">מוריד הודעת MMS</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">שגיאה בהורדת הודעת MMS, הקש כדי לנסות שוב</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">שלח אל %s</string>
|
<string name="MediaPickerActivity_send_to">שלח אל %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -166,9 +166,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">בחר הכל</string>
|
<string name="MediaOverviewActivity_Select_all">בחר הכל</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">אוסף צרופות...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">אוסף צרופות...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">הודעת מולטימדיה</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">מוריד הודעת MMS</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">שגיאה בהורדת הודעת MMS, הקש כדי לנסות שוב</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">שלח אל %s</string>
|
<string name="MediaPickerActivity_send_to">שלח אל %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -140,9 +140,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">すべて選択</string>
|
<string name="MediaOverviewActivity_Select_all">すべて選択</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">添付ファイルを集めています...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">添付ファイルを集めています...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">マルチメディアメッセージ</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">MMSメッセージをダウンロード中</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">MMSメッセージのダウンロード中にエラーが発生しました。タップして再試行してください。</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">%sに送信</string>
|
<string name="MediaPickerActivity_send_to">%sに送信</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -140,9 +140,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">すべて選択</string>
|
<string name="MediaOverviewActivity_Select_all">すべて選択</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">添付ファイルを集めています...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">添付ファイルを集めています...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">マルチメディアメッセージ</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">MMSメッセージをダウンロード中</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">MMSメッセージのダウンロード中にエラーが発生しました。タップして再試行してください。</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">%sに送信</string>
|
<string name="MediaPickerActivity_send_to">%sに送信</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -127,9 +127,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">ជ្រើសរើសទាំងអស់</string>
|
<string name="MediaOverviewActivity_Select_all">ជ្រើសរើសទាំងអស់</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">កំពុងប្រមូលឯកសារភ្ជាប់...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">កំពុងប្រមូលឯកសារភ្ជាប់...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">សារចម្រុះ</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">កំពុងទាញយកសារ MMS </string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">មានបញ្ហាទាញយកសារMMS សូមចុច ដើម្បីព្យាយាមម្តងទៀត</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">ផ្ញើទៅកាន់ %s</string>
|
<string name="MediaPickerActivity_send_to">ផ្ញើទៅកាន់ %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -127,9 +127,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">ជ្រើសរើសទាំងអស់</string>
|
<string name="MediaOverviewActivity_Select_all">ជ្រើសរើសទាំងអស់</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">កំពុងប្រមូលឯកសារភ្ជាប់...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">កំពុងប្រមូលឯកសារភ្ជាប់...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">សារចម្រុះ</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">កំពុងទាញយកសារ MMS </string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">មានបញ្ហាទាញយកសារMMS សូមចុច ដើម្បីព្យាយាមម្តងទៀត</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">ផ្ញើទៅកាន់ %s</string>
|
<string name="MediaPickerActivity_send_to">ផ្ញើទៅកាន់ %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -75,7 +75,6 @@
|
|||||||
<string name="MediaOverviewActivity_Documents">ದಾಖಲೆಗಳು</string>
|
<string name="MediaOverviewActivity_Documents">ದಾಖಲೆಗಳು</string>
|
||||||
<string name="MediaOverviewActivity_Select_all">ಎಲ್ಲ ಆಯ್ದುಕೊಳ್ಳಿ</string>
|
<string name="MediaOverviewActivity_Select_all">ಎಲ್ಲ ಆಯ್ದುಕೊಳ್ಳಿ</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">ಮಲ್ಟಿಮೀಡಿಯಾ ಸಂದೇಶ</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
<!-- MediaRepository -->
|
<!-- MediaRepository -->
|
||||||
|
@ -75,7 +75,6 @@
|
|||||||
<string name="MediaOverviewActivity_Documents">ದಾಖಲೆಗಳು</string>
|
<string name="MediaOverviewActivity_Documents">ದಾಖಲೆಗಳು</string>
|
||||||
<string name="MediaOverviewActivity_Select_all">ಎಲ್ಲ ಆಯ್ದುಕೊಳ್ಳಿ</string>
|
<string name="MediaOverviewActivity_Select_all">ಎಲ್ಲ ಆಯ್ದುಕೊಳ್ಳಿ</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">ಮಲ್ಟಿಮೀಡಿಯಾ ಸಂದೇಶ</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
<!-- MediaRepository -->
|
<!-- MediaRepository -->
|
||||||
|
@ -136,9 +136,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">모두 선택</string>
|
<string name="MediaOverviewActivity_Select_all">모두 선택</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">첨부파일 저장 준비 중…</string>
|
<string name="MediaOverviewActivity_collecting_attachments">첨부파일 저장 준비 중…</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">멀티미디어 메시지</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">MMS 메시지 내려 받는 중</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">MMS 내려 받기 오류, 다시 보내려면 다시 시도를 눌러주세요.</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">%s에게 전송</string>
|
<string name="MediaPickerActivity_send_to">%s에게 전송</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -136,9 +136,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">모두 선택</string>
|
<string name="MediaOverviewActivity_Select_all">모두 선택</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">첨부파일 저장 준비 중…</string>
|
<string name="MediaOverviewActivity_collecting_attachments">첨부파일 저장 준비 중…</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">멀티미디어 메시지</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">MMS 메시지 내려 받는 중</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">MMS 내려 받기 오류, 다시 보내려면 다시 시도를 눌러주세요.</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">%s에게 전송</string>
|
<string name="MediaPickerActivity_send_to">%s에게 전송</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -166,9 +166,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Žymėti visus</string>
|
<string name="MediaOverviewActivity_Select_all">Žymėti visus</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Renkami priedai...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Renkami priedai...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Multimedijos žinutė</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Atsiunčiama MMS žinutė</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Klaida, atsiunčiant MMS žinutę, bakstelėkite, norėdami bandyti dar kartą</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Siųsti adresatui %s</string>
|
<string name="MediaPickerActivity_send_to">Siųsti adresatui %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -166,9 +166,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Žymėti visus</string>
|
<string name="MediaOverviewActivity_Select_all">Žymėti visus</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Renkami priedai...</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Renkami priedai...</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Multimedijos žinutė</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Atsiunčiama MMS žinutė</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Klaida, atsiunčiant MMS žinutę, bakstelėkite, norėdami bandyti dar kartą</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Siųsti adresatui %s</string>
|
<string name="MediaPickerActivity_send_to">Siųsti adresatui %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -87,9 +87,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">အားလုံးကို ရွေးပါ</string>
|
<string name="MediaOverviewActivity_Select_all">အားလုံးကို ရွေးပါ</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">ပူးတွဲဖိုင်များကို စုစည်းနေသည် </string>
|
<string name="MediaOverviewActivity_collecting_attachments">ပူးတွဲဖိုင်များကို စုစည်းနေသည် </string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">ရုပ်၊သံပါ အချက်အလက်များ</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">MMS များအား ဒေါင်းလုပ်ဆွဲမည်</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">MMS များအားဒေါင်းလုပ်ဆွဲနေစဉ် ရပ်တန့်သွားသည်၊ ပြန်စရန် နှိပ်ပါ</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
<!-- MediaRepository -->
|
<!-- MediaRepository -->
|
||||||
|
@ -87,9 +87,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">အားလုံးကို ရွေးပါ</string>
|
<string name="MediaOverviewActivity_Select_all">အားလုံးကို ရွေးပါ</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">ပူးတွဲဖိုင်များကို စုစည်းနေသည် </string>
|
<string name="MediaOverviewActivity_collecting_attachments">ပူးတွဲဖိုင်များကို စုစည်းနေသည် </string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">ရုပ်၊သံပါ အချက်အလက်များ</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">MMS များအား ဒေါင်းလုပ်ဆွဲမည်</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">MMS များအားဒေါင်းလုပ်ဆွဲနေစဉ် ရပ်တန့်သွားသည်၊ ပြန်စရန် နှိပ်ပါ</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
<!-- MediaRepository -->
|
<!-- MediaRepository -->
|
||||||
|
@ -150,9 +150,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Velg alle</string>
|
<string name="MediaOverviewActivity_Select_all">Velg alle</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Henter vedlegg …</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Henter vedlegg …</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Multimediemelding</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Laster ned MMS-melding</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Feil under nedlasting av MMS-melding. Trykk for å prøve igjen</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Send til %s</string>
|
<string name="MediaPickerActivity_send_to">Send til %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
@ -554,7 +551,7 @@ nøkkelutvekslingsmelding.</string>
|
|||||||
<string name="activity_home_delete_conversation_dialog_message">Er du sikker på at du vil slette denne samtalen?</string>
|
<string name="activity_home_delete_conversation_dialog_message">Er du sikker på at du vil slette denne samtalen?</string>
|
||||||
<string name="activity_home_conversation_deleted_message">Samtalen slettet</string>
|
<string name="activity_home_conversation_deleted_message">Samtalen slettet</string>
|
||||||
<string name="view_seed_reminder_subtitle_1">Sikre kontoen din ved å lagre din gjenopprettingsfrase</string>
|
<string name="view_seed_reminder_subtitle_1">Sikre kontoen din ved å lagre din gjenopprettingsfrase</string>
|
||||||
<string name="view_seed_reminder_subtitle_2">Trykk og hold inne de overflødige ordene for å hente gjenopprettingsfrasen din, og lagre den trygt å sikre din Session-ID.</string>
|
<string name="view_seed_reminder_subtitle_2">Trykk og hold inne de overflødige ordene for å hente gjenopprettingsfrasen din, og lagre den trygt å sikre din Account-ID.</string>
|
||||||
<string name="view_seed_reminder_subtitle_3">Pass på å lagre gjenopprettingsfrasen på et sikkert sted</string>
|
<string name="view_seed_reminder_subtitle_3">Pass på å lagre gjenopprettingsfrasen på et sikkert sted</string>
|
||||||
<string name="activity_path_title">Bane</string>
|
<string name="activity_path_title">Bane</string>
|
||||||
<string name="activity_path_explanation">Session skjuler din IP ved å laste ned meldingene dine gjennom flere Service Noder i Sessions desentraliserte nettverk. Disse er landene som koblingen din for øyeblikket blir kontaktet gjennom:</string>
|
<string name="activity_path_explanation">Session skjuler din IP ved å laste ned meldingene dine gjennom flere Service Noder i Sessions desentraliserte nettverk. Disse er landene som koblingen din for øyeblikket blir kontaktet gjennom:</string>
|
||||||
@ -568,9 +565,9 @@ nøkkelutvekslingsmelding.</string>
|
|||||||
<string name="activity_create_private_chat_enter_account_id_tab_title">Skriv inn Account ID</string>
|
<string name="activity_create_private_chat_enter_account_id_tab_title">Skriv inn Account ID</string>
|
||||||
<string name="activity_create_private_chat_scan_qr_code_tab_title">Skann QR-kode</string>
|
<string name="activity_create_private_chat_scan_qr_code_tab_title">Skann QR-kode</string>
|
||||||
<string name="activity_create_private_chat_scan_qr_code_explanation">Skann en brukers QR-kode for å starte en økt. QR-koder finnes ved å trykke på QR-koden i kontoinnstillingene.</string>
|
<string name="activity_create_private_chat_scan_qr_code_explanation">Skann en brukers QR-kode for å starte en økt. QR-koder finnes ved å trykke på QR-koden i kontoinnstillingene.</string>
|
||||||
<string name="fragment_enter_public_key_edit_text_hint">Angi Session-ID eller ONS-navn</string>
|
<string name="fragment_enter_public_key_edit_text_hint">Angi Account-ID eller ONS-navn</string>
|
||||||
<string name="fragment_enter_public_key_explanation">Brukere kan dele sin Session-ID ved å gå inn i sine kontoinnstillinger og trykke på \"Del Session-ID\", eller ved å dele sin QR-kode.</string>
|
<string name="fragment_enter_public_key_explanation">Brukere kan dele sin Account-ID ved å gå inn i sine kontoinnstillinger og trykke på \"Del Account-ID\", eller ved å dele sin QR-kode.</string>
|
||||||
<string name="fragment_enter_public_key_error_message">Vennligst sjekk Session-ID\'en eller ONS-navnet og prøv igjen.</string>
|
<string name="fragment_enter_public_key_error_message">Vennligst sjekk Account-ID\'en eller ONS-navnet og prøv igjen.</string>
|
||||||
<string name="fragment_scan_qr_code_camera_access_explanation">Session trenger kameratilgang for å skanne QR-koder</string>
|
<string name="fragment_scan_qr_code_camera_access_explanation">Session trenger kameratilgang for å skanne QR-koder</string>
|
||||||
<string name="fragment_scan_qr_code_grant_camera_access_button_title">Gi kameratilgang</string>
|
<string name="fragment_scan_qr_code_grant_camera_access_button_title">Gi kameratilgang</string>
|
||||||
<string name="activity_create_closed_group_title">Ny lukket gruppe</string>
|
<string name="activity_create_closed_group_title">Ny lukket gruppe</string>
|
||||||
@ -642,7 +639,7 @@ nøkkelutvekslingsmelding.</string>
|
|||||||
<string name="dialog_ui_mode_option_day">Dag</string>
|
<string name="dialog_ui_mode_option_day">Dag</string>
|
||||||
<string name="dialog_ui_mode_option_night">Natt</string>
|
<string name="dialog_ui_mode_option_night">Natt</string>
|
||||||
<string name="dialog_ui_mode_option_system_default">Systemstandard</string>
|
<string name="dialog_ui_mode_option_system_default">Systemstandard</string>
|
||||||
<string name="activity_conversation_menu_copy_account_id">Kopier Session-ID</string>
|
<string name="activity_conversation_menu_copy_account_id">Kopier Account-ID</string>
|
||||||
<string name="attachment">Vedlegg</string>
|
<string name="attachment">Vedlegg</string>
|
||||||
<string name="attachment_type_voice_message">Talemelding</string>
|
<string name="attachment_type_voice_message">Talemelding</string>
|
||||||
<string name="details">Detaljer</string>
|
<string name="details">Detaljer</string>
|
||||||
|
@ -150,9 +150,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Velg alle</string>
|
<string name="MediaOverviewActivity_Select_all">Velg alle</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Henter vedlegg …</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Henter vedlegg …</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Multimediemelding</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Laster ned MMS-melding</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Feil under nedlasting av MMS-melding. Trykk for å prøve igjen</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Send til %s</string>
|
<string name="MediaPickerActivity_send_to">Send til %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
@ -554,7 +551,7 @@ nøkkelutvekslingsmelding.</string>
|
|||||||
<string name="activity_home_delete_conversation_dialog_message">Er du sikker på at du vil slette denne samtalen?</string>
|
<string name="activity_home_delete_conversation_dialog_message">Er du sikker på at du vil slette denne samtalen?</string>
|
||||||
<string name="activity_home_conversation_deleted_message">Samtalen slettet</string>
|
<string name="activity_home_conversation_deleted_message">Samtalen slettet</string>
|
||||||
<string name="view_seed_reminder_subtitle_1">Sikre kontoen din ved å lagre din gjenopprettingsfrase</string>
|
<string name="view_seed_reminder_subtitle_1">Sikre kontoen din ved å lagre din gjenopprettingsfrase</string>
|
||||||
<string name="view_seed_reminder_subtitle_2">Trykk og hold inne de overflødige ordene for å hente gjenopprettingsfrasen din, og lagre den trygt å sikre din Session-ID.</string>
|
<string name="view_seed_reminder_subtitle_2">Trykk og hold inne de overflødige ordene for å hente gjenopprettingsfrasen din, og lagre den trygt å sikre din Account-ID.</string>
|
||||||
<string name="view_seed_reminder_subtitle_3">Pass på å lagre gjenopprettingsfrasen på et sikkert sted</string>
|
<string name="view_seed_reminder_subtitle_3">Pass på å lagre gjenopprettingsfrasen på et sikkert sted</string>
|
||||||
<string name="activity_path_title">Bane</string>
|
<string name="activity_path_title">Bane</string>
|
||||||
<string name="activity_path_explanation">Session skjuler din IP ved å laste ned meldingene dine gjennom flere Service Noder i Sessions desentraliserte nettverk. Disse er landene som koblingen din for øyeblikket blir kontaktet gjennom:</string>
|
<string name="activity_path_explanation">Session skjuler din IP ved å laste ned meldingene dine gjennom flere Service Noder i Sessions desentraliserte nettverk. Disse er landene som koblingen din for øyeblikket blir kontaktet gjennom:</string>
|
||||||
@ -568,9 +565,9 @@ nøkkelutvekslingsmelding.</string>
|
|||||||
<string name="activity_create_private_chat_enter_account_id_tab_title">Skriv inn Account ID</string>
|
<string name="activity_create_private_chat_enter_account_id_tab_title">Skriv inn Account ID</string>
|
||||||
<string name="activity_create_private_chat_scan_qr_code_tab_title">Skann QR-kode</string>
|
<string name="activity_create_private_chat_scan_qr_code_tab_title">Skann QR-kode</string>
|
||||||
<string name="activity_create_private_chat_scan_qr_code_explanation">Skann en brukers QR-kode for å starte en økt. QR-koder finnes ved å trykke på QR-koden i kontoinnstillingene.</string>
|
<string name="activity_create_private_chat_scan_qr_code_explanation">Skann en brukers QR-kode for å starte en økt. QR-koder finnes ved å trykke på QR-koden i kontoinnstillingene.</string>
|
||||||
<string name="fragment_enter_public_key_edit_text_hint">Angi Session-ID eller ONS-navn</string>
|
<string name="fragment_enter_public_key_edit_text_hint">Angi Account-ID eller ONS-navn</string>
|
||||||
<string name="fragment_enter_public_key_explanation">Brukere kan dele sin Session-ID ved å gå inn i sine kontoinnstillinger og trykke på \"Del Session-ID\", eller ved å dele sin QR-kode.</string>
|
<string name="fragment_enter_public_key_explanation">Brukere kan dele sin Account-ID ved å gå inn i sine kontoinnstillinger og trykke på \"Del Account-ID\", eller ved å dele sin QR-kode.</string>
|
||||||
<string name="fragment_enter_public_key_error_message">Vennligst sjekk Session-ID\'en eller ONS-navnet og prøv igjen.</string>
|
<string name="fragment_enter_public_key_error_message">Vennligst sjekk Account-ID\'en eller ONS-navnet og prøv igjen.</string>
|
||||||
<string name="fragment_scan_qr_code_camera_access_explanation">Session trenger kameratilgang for å skanne QR-koder</string>
|
<string name="fragment_scan_qr_code_camera_access_explanation">Session trenger kameratilgang for å skanne QR-koder</string>
|
||||||
<string name="fragment_scan_qr_code_grant_camera_access_button_title">Gi kameratilgang</string>
|
<string name="fragment_scan_qr_code_grant_camera_access_button_title">Gi kameratilgang</string>
|
||||||
<string name="activity_create_closed_group_title">Ny lukket gruppe</string>
|
<string name="activity_create_closed_group_title">Ny lukket gruppe</string>
|
||||||
@ -642,7 +639,7 @@ nøkkelutvekslingsmelding.</string>
|
|||||||
<string name="dialog_ui_mode_option_day">Dag</string>
|
<string name="dialog_ui_mode_option_day">Dag</string>
|
||||||
<string name="dialog_ui_mode_option_night">Natt</string>
|
<string name="dialog_ui_mode_option_night">Natt</string>
|
||||||
<string name="dialog_ui_mode_option_system_default">Systemstandard</string>
|
<string name="dialog_ui_mode_option_system_default">Systemstandard</string>
|
||||||
<string name="activity_conversation_menu_copy_account_id">Kopier Session-ID</string>
|
<string name="activity_conversation_menu_copy_account_id">Kopier Account-ID</string>
|
||||||
<string name="attachment">Vedlegg</string>
|
<string name="attachment">Vedlegg</string>
|
||||||
<string name="attachment_type_voice_message">Talemelding</string>
|
<string name="attachment_type_voice_message">Talemelding</string>
|
||||||
<string name="details">Detaljer</string>
|
<string name="details">Detaljer</string>
|
||||||
|
@ -150,9 +150,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Alles selecteren</string>
|
<string name="MediaOverviewActivity_Select_all">Alles selecteren</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Bijlagen aan het verzamelen…</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Bijlagen aan het verzamelen…</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Multimediabericht</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Mms-bericht aan het downloaden</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Fout bij downloaden van mms-bericht, tik om opnieuw te proberen</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Verzenden naar %s</string>
|
<string name="MediaPickerActivity_send_to">Verzenden naar %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
@ -570,7 +567,7 @@
|
|||||||
<string name="activity_create_private_chat_scan_qr_code_tab_title">Scan QR-code</string>
|
<string name="activity_create_private_chat_scan_qr_code_tab_title">Scan QR-code</string>
|
||||||
<string name="activity_create_private_chat_scan_qr_code_explanation">Scan de QR-code van een gebruiker om een sessie te starten. QR-codes kunnen worden gevonden door op het QR-icoon in de accountinstellingen te tikken.</string>
|
<string name="activity_create_private_chat_scan_qr_code_explanation">Scan de QR-code van een gebruiker om een sessie te starten. QR-codes kunnen worden gevonden door op het QR-icoon in de accountinstellingen te tikken.</string>
|
||||||
<string name="fragment_enter_public_key_edit_text_hint">Voer uw Account ID of ONS naam in</string>
|
<string name="fragment_enter_public_key_edit_text_hint">Voer uw Account ID of ONS naam in</string>
|
||||||
<string name="fragment_enter_public_key_explanation">Gebruikers kunnen hun Session-ID delen door naar hun accountinstellingen te gaan en op \"Deel Session-ID\" te tikken, of door hun QR-code te delen.</string>
|
<string name="fragment_enter_public_key_explanation">Gebruikers kunnen hun Account-ID delen door naar hun accountinstellingen te gaan en op \"Deel Account-ID\" te tikken, of door hun QR-code te delen.</string>
|
||||||
<string name="fragment_enter_public_key_error_message">Controleer de sessie-ID of ONS naam en probeer het opnieuw.</string>
|
<string name="fragment_enter_public_key_error_message">Controleer de sessie-ID of ONS naam en probeer het opnieuw.</string>
|
||||||
<string name="fragment_scan_qr_code_camera_access_explanation">Sessie heeft cameratoegang nodig om QR-codes te scannen</string>
|
<string name="fragment_scan_qr_code_camera_access_explanation">Sessie heeft cameratoegang nodig om QR-codes te scannen</string>
|
||||||
<string name="fragment_scan_qr_code_grant_camera_access_button_title">Toegang tot camera verlenen</string>
|
<string name="fragment_scan_qr_code_grant_camera_access_button_title">Toegang tot camera verlenen</string>
|
||||||
|
@ -150,9 +150,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Alles selecteren</string>
|
<string name="MediaOverviewActivity_Select_all">Alles selecteren</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Bijlagen aan het verzamelen…</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Bijlagen aan het verzamelen…</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Multimediabericht</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Mms-bericht aan het downloaden</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Fout bij downloaden van mms-bericht, tik om opnieuw te proberen</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Verzenden naar %s</string>
|
<string name="MediaPickerActivity_send_to">Verzenden naar %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
@ -570,7 +567,7 @@
|
|||||||
<string name="activity_create_private_chat_scan_qr_code_tab_title">Scan QR-code</string>
|
<string name="activity_create_private_chat_scan_qr_code_tab_title">Scan QR-code</string>
|
||||||
<string name="activity_create_private_chat_scan_qr_code_explanation">Scan de QR-code van een gebruiker om een sessie te starten. QR-codes kunnen worden gevonden door op het QR-icoon in de accountinstellingen te tikken.</string>
|
<string name="activity_create_private_chat_scan_qr_code_explanation">Scan de QR-code van een gebruiker om een sessie te starten. QR-codes kunnen worden gevonden door op het QR-icoon in de accountinstellingen te tikken.</string>
|
||||||
<string name="fragment_enter_public_key_edit_text_hint">Voer uw Account ID of ONS naam in</string>
|
<string name="fragment_enter_public_key_edit_text_hint">Voer uw Account ID of ONS naam in</string>
|
||||||
<string name="fragment_enter_public_key_explanation">Gebruikers kunnen hun Session-ID delen door naar hun accountinstellingen te gaan en op \"Deel Session-ID\" te tikken, of door hun QR-code te delen.</string>
|
<string name="fragment_enter_public_key_explanation">Gebruikers kunnen hun Account-ID delen door naar hun accountinstellingen te gaan en op \"Deel Account-ID\" te tikken, of door hun QR-code te delen.</string>
|
||||||
<string name="fragment_enter_public_key_error_message">Controleer de sessie-ID of ONS naam en probeer het opnieuw.</string>
|
<string name="fragment_enter_public_key_error_message">Controleer de sessie-ID of ONS naam en probeer het opnieuw.</string>
|
||||||
<string name="fragment_scan_qr_code_camera_access_explanation">Sessie heeft cameratoegang nodig om QR-codes te scannen</string>
|
<string name="fragment_scan_qr_code_camera_access_explanation">Sessie heeft cameratoegang nodig om QR-codes te scannen</string>
|
||||||
<string name="fragment_scan_qr_code_grant_camera_access_button_title">Toegang tot camera verlenen</string>
|
<string name="fragment_scan_qr_code_grant_camera_access_button_title">Toegang tot camera verlenen</string>
|
||||||
|
@ -132,9 +132,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Vel alle</string>
|
<string name="MediaOverviewActivity_Select_all">Vel alle</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Hentar vedlegg …</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Hentar vedlegg …</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Multimediemelding</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Lastar ned MMS-melding</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Klarte ikkje lasta ned MMS-melding, trykk for å prøva igjen</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Send til %s</string>
|
<string name="MediaPickerActivity_send_to">Send til %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
@ -132,9 +132,6 @@
|
|||||||
<string name="MediaOverviewActivity_Select_all">Vel alle</string>
|
<string name="MediaOverviewActivity_Select_all">Vel alle</string>
|
||||||
<string name="MediaOverviewActivity_collecting_attachments">Hentar vedlegg …</string>
|
<string name="MediaOverviewActivity_collecting_attachments">Hentar vedlegg …</string>
|
||||||
<!-- NotificationMmsMessageRecord -->
|
<!-- NotificationMmsMessageRecord -->
|
||||||
<string name="NotificationMmsMessageRecord_multimedia_message">Multimediemelding</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_downloading_mms_message">Lastar ned MMS-melding</string>
|
|
||||||
<string name="NotificationMmsMessageRecord_error_downloading_mms_message">Klarte ikkje lasta ned MMS-melding, trykk for å prøva igjen</string>
|
|
||||||
<!-- MediaPickerActivity -->
|
<!-- MediaPickerActivity -->
|
||||||
<string name="MediaPickerActivity_send_to">Send til %s</string>
|
<string name="MediaPickerActivity_send_to">Send til %s</string>
|
||||||
<!-- MediaSendActivity -->
|
<!-- MediaSendActivity -->
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user