mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-08-12 08:13:28 +01:00
Fix a bunch of lint issues.
This commit is contained in:
@@ -600,7 +600,18 @@ public final class ContactSelectionListFragment extends LoggingFragment {
|
||||
boolean isUnknown = contact instanceof ContactSearchKey.UnknownRecipientKey;
|
||||
SelectedContact selectedContact = contact.requireSelectedContact();
|
||||
|
||||
if (!canSelectSelf && !selectedContact.hasUsername() && Recipient.self().getId().equals(selectedContact.getOrCreateRecipientId())) {
|
||||
boolean needsSelfCheck = !canSelectSelf && !selectedContact.hasUsername();
|
||||
|
||||
if (needsSelfCheck) {
|
||||
lifecycleDisposable.add(contactChipViewModel.isSelf(selectedContact)
|
||||
.subscribe(isSelf -> onItemClickResolved(contact, selectedContact, isUnknown, isSelf)));
|
||||
} else {
|
||||
onItemClickResolved(contact, selectedContact, isUnknown, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void onItemClickResolved(ContactSearchKey contact, SelectedContact selectedContact, boolean isUnknown, boolean isSelf) {
|
||||
if (isSelf) {
|
||||
Toast.makeText(requireContext(), R.string.ContactSelectionListFragment_you_do_not_need_to_add_yourself_to_the_group, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
+10
-90
@@ -1,107 +1,27 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.os.Bundle;
|
||||
import android.provider.ContactsContract;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.activity.ComponentActivity;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.conversation.ConversationIntents;
|
||||
import org.thoughtcrime.securesms.conversation.NewConversationActivity;
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.Rfc5724Uri;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
public class SystemContactsEntrypointActivity extends Activity {
|
||||
|
||||
private static final String TAG = Log.tag(SystemContactsEntrypointActivity.class);
|
||||
public class SystemContactsEntrypointActivity extends ComponentActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
startActivity(getNextIntent(getIntent()));
|
||||
finish();
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
private Intent getNextIntent(Intent original) {
|
||||
DestinationAndBody destination;
|
||||
SystemContactsEntrypointViewModel viewModel = new ViewModelProvider(this).get(SystemContactsEntrypointViewModel.class);
|
||||
|
||||
if (original.getData() != null && "content".equals(original.getData().getScheme())) {
|
||||
destination = getDestinationForSyncAdapter(original);
|
||||
} else {
|
||||
destination = getDestinationForView(original);
|
||||
}
|
||||
|
||||
final Intent nextIntent;
|
||||
|
||||
if (TextUtils.isEmpty(destination.destination)) {
|
||||
nextIntent = NewConversationActivity.createIntent(this, destination.getBody());
|
||||
Toast.makeText(this, R.string.ConversationActivity_specify_recipient, Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
Recipient recipient = Recipient.external(destination.getDestination());
|
||||
|
||||
if (recipient != null) {
|
||||
long threadId = SignalDatabase.threads().getOrCreateThreadIdFor(recipient);
|
||||
|
||||
nextIntent = ConversationIntents.createBuilderSync(this, recipient.getId(), threadId)
|
||||
.withDraftText(destination.getBody())
|
||||
.build();
|
||||
} else {
|
||||
nextIntent = NewConversationActivity.createIntent(this, destination.getBody());
|
||||
viewModel.getContactAction().observe(this, nextStep -> {
|
||||
if (nextStep.getShowSpecifyRecipientToast()) {
|
||||
Toast.makeText(this, R.string.ConversationActivity_specify_recipient, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
return nextIntent;
|
||||
}
|
||||
startActivity(nextStep.getIntent());
|
||||
finish();
|
||||
});
|
||||
|
||||
private @NonNull DestinationAndBody getDestinationForView(Intent intent) {
|
||||
try {
|
||||
Rfc5724Uri smsUri = new Rfc5724Uri(intent.getData().toString());
|
||||
return new DestinationAndBody(smsUri.getPath(), smsUri.getQueryParams().get("body"));
|
||||
} catch (URISyntaxException e) {
|
||||
Log.w(TAG, "unable to parse RFC5724 URI from intent", e);
|
||||
return new DestinationAndBody("", "");
|
||||
}
|
||||
}
|
||||
|
||||
private @NonNull DestinationAndBody getDestinationForSyncAdapter(Intent intent) {
|
||||
Cursor cursor = null;
|
||||
|
||||
try {
|
||||
cursor = getContentResolver().query(intent.getData(), null, null, null, null);
|
||||
|
||||
if (cursor != null && cursor.moveToNext()) {
|
||||
return new DestinationAndBody(cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.RawContacts.Data.DATA1)), "");
|
||||
}
|
||||
|
||||
return new DestinationAndBody("", "");
|
||||
} finally {
|
||||
if (cursor != null) cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static class DestinationAndBody {
|
||||
private final String destination;
|
||||
private final String body;
|
||||
|
||||
private DestinationAndBody(String destination, String body) {
|
||||
this.destination = destination;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public String getDestination() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
public String getBody() {
|
||||
return body;
|
||||
}
|
||||
viewModel.resolveNextStep(getIntent());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
package org.thoughtcrime.securesms
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.provider.ContactsContract
|
||||
import android.text.TextUtils
|
||||
import androidx.annotation.WorkerThread
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.conversation.ConversationIntents
|
||||
import org.thoughtcrime.securesms.conversation.NewConversationActivity
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.util.Rfc5724Uri
|
||||
import java.net.URISyntaxException
|
||||
|
||||
class SystemContactsEntrypointViewModel : ViewModel() {
|
||||
|
||||
companion object {
|
||||
private val TAG = Log.tag(SystemContactsEntrypointViewModel::class.java)
|
||||
}
|
||||
|
||||
private val internalContactAction = MutableLiveData<ContactAction>()
|
||||
val contactAction: LiveData<ContactAction> = internalContactAction
|
||||
|
||||
fun resolveNextStep(original: Intent) {
|
||||
viewModelScope.launch {
|
||||
val result = withContext(Dispatchers.IO) {
|
||||
getContactAction(AppDependencies.application, original)
|
||||
}
|
||||
|
||||
internalContactAction.value = result
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private fun getContactAction(context: Context, original: Intent): ContactAction {
|
||||
val destination = if (original.data != null && "content" == original.data?.scheme) {
|
||||
getDestinationForSyncAdapter(context, original)
|
||||
} else {
|
||||
getDestinationForView(original)
|
||||
}
|
||||
|
||||
val destinationAddress = destination.destination
|
||||
if (TextUtils.isEmpty(destinationAddress)) {
|
||||
return ContactAction(NewConversationActivity.createIntent(context, destination.body), true)
|
||||
}
|
||||
|
||||
val recipient = Recipient.external(destinationAddress!!)
|
||||
|
||||
if (recipient != null) {
|
||||
val threadId = SignalDatabase.threads.getOrCreateThreadIdFor(recipient)
|
||||
|
||||
val nextIntent = ConversationIntents.createBuilderSync(context, recipient.id, threadId)
|
||||
.withDraftText(destination.body)
|
||||
.build()
|
||||
|
||||
return ContactAction(nextIntent, false)
|
||||
}
|
||||
|
||||
return ContactAction(NewConversationActivity.createIntent(context, destination.body), true)
|
||||
}
|
||||
|
||||
private fun getDestinationForView(intent: Intent): DestinationAndBody {
|
||||
return try {
|
||||
val smsUri = Rfc5724Uri(intent.data.toString())
|
||||
DestinationAndBody(smsUri.path, smsUri.queryParams["body"])
|
||||
} catch (e: URISyntaxException) {
|
||||
Log.w(TAG, "unable to parse RFC5724 URI from intent", e)
|
||||
DestinationAndBody("", "")
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDestinationForSyncAdapter(context: Context, intent: Intent): DestinationAndBody {
|
||||
context.contentResolver.query(intent.data!!, null, null, null, null).use { cursor ->
|
||||
if (cursor != null && cursor.moveToNext()) {
|
||||
return DestinationAndBody(cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.RawContacts.Data.DATA1)), "")
|
||||
}
|
||||
|
||||
return DestinationAndBody("", "")
|
||||
}
|
||||
}
|
||||
|
||||
data class ContactAction(
|
||||
val intent: Intent,
|
||||
val showSpecifyRecipientToast: Boolean
|
||||
)
|
||||
|
||||
private data class DestinationAndBody(
|
||||
val destination: String?,
|
||||
val body: String?
|
||||
)
|
||||
}
|
||||
@@ -72,6 +72,12 @@ class ContactChipViewModel : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
fun isSelf(selectedContact: SelectedContact): Single<Boolean> {
|
||||
return Single.fromCallable { Recipient.self().id == selectedContact.getOrCreateRecipientId() }
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
private fun getOrCreateRecipientId(selectedContact: SelectedContact): Single<RecipientId> {
|
||||
return Single.fromCallable {
|
||||
selectedContact.getOrCreateRecipientId()
|
||||
|
||||
@@ -45,7 +45,6 @@ object JumboEmoji {
|
||||
private var currentVersion: Int = -1
|
||||
|
||||
@JvmStatic
|
||||
@MainThread
|
||||
fun updateCurrentVersion(context: Context) {
|
||||
SignalExecutors.BOUNDED.execute {
|
||||
val version: EmojiFiles.Version = EmojiFiles.Version.readVersion(context, true) ?: return@execute
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.longmessage;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import org.thoughtcrime.securesms.conversation.ConversationMessage;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
@@ -14,16 +15,19 @@ import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
class LongMessage {
|
||||
|
||||
private final ConversationMessage conversationMessage;
|
||||
private final CharSequence fullBody;
|
||||
|
||||
LongMessage(@NonNull ConversationMessage conversationMessage) {
|
||||
@WorkerThread
|
||||
LongMessage(@NonNull ConversationMessage conversationMessage, @NonNull Context context) {
|
||||
this.conversationMessage = conversationMessage;
|
||||
this.fullBody = conversationMessage.getDisplayBody(context);
|
||||
}
|
||||
|
||||
@NonNull MessageRecord getMessageRecord() {
|
||||
return conversationMessage.getMessageRecord();
|
||||
}
|
||||
|
||||
@NonNull CharSequence getFullBody(@NonNull Context context) {
|
||||
return conversationMessage.getDisplayBody(context);
|
||||
@NonNull CharSequence getFullBody() {
|
||||
return fullBody;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ public class LongMessageFragment extends FullScreenDialogFragment {
|
||||
EmojiTextView text = bubble.findViewById(R.id.longmessage_text);
|
||||
ConversationItemFooter footer = bubble.findViewById(R.id.longmessage_footer);
|
||||
|
||||
SpannableString body = new SpannableString(getTrimmedBody(message.get().getFullBody(requireContext())));
|
||||
SpannableString body = new SpannableString(getTrimmedBody(message.get().getFullBody()));
|
||||
V2ConversationItemUtils.linkifyUrlLinks(body,
|
||||
true,
|
||||
url -> CommunicationActions.handlePotentialGroupLinkUrl(requireActivity(), url) ||
|
||||
|
||||
@@ -37,7 +37,7 @@ class LongMessageRepository {
|
||||
Optional<MmsMessageRecord> record = getMmsMessage(mmsDatabase, messageId);
|
||||
if (record.isPresent()) {
|
||||
final ConversationMessage resolvedMessage = LongMessageResolveerKt.resolveBody(record.get(), context);
|
||||
return Optional.of(new LongMessage(resolvedMessage));
|
||||
return Optional.of(new LongMessage(resolvedMessage, context));
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
+25
-74
@@ -1,22 +1,18 @@
|
||||
package org.thoughtcrime.securesms.mediasend
|
||||
|
||||
import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.provider.OpenableColumns
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import org.signal.core.models.media.Media
|
||||
import org.signal.core.util.bytes
|
||||
import org.signal.core.util.getParcelableCompat
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.mms.PartAuthority
|
||||
import org.thoughtcrime.securesms.util.MediaUtil
|
||||
import java.io.IOException
|
||||
import java.util.Optional
|
||||
import org.thoughtcrime.securesms.mediasend.MediaSendDocumentViewModel.DocumentInfo
|
||||
import org.signal.core.ui.R as CoreUiR
|
||||
|
||||
/**
|
||||
@@ -43,6 +39,10 @@ class MediaSendDocumentFragment : Fragment(R.layout.mediasend_document_fragment)
|
||||
private lateinit var uri: Uri
|
||||
private lateinit var media: Media
|
||||
|
||||
private val viewModel: MediaSendDocumentViewModel by viewModels {
|
||||
MediaSendDocumentViewModel.Factory(media)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
@@ -52,24 +52,28 @@ class MediaSendDocumentFragment : Fragment(R.layout.mediasend_document_fragment)
|
||||
|
||||
this.media = requireNotNull(requireArguments().getParcelableCompat(KEY_MEDIA, Media::class.java))
|
||||
|
||||
val fileInfo: Pair<String?, Long>? = getFileInfo()
|
||||
if (fileInfo != null) {
|
||||
media.fileName = fileInfo.first
|
||||
name.text = fileInfo.first ?: getString(R.string.DocumentView_unnamed_file)
|
||||
size.text = fileInfo.second.bytes.toUnitString()
|
||||
viewModel.documentInfo.observe(viewLifecycleOwner) { documentInfoOptional ->
|
||||
val documentInfo: DocumentInfo? = documentInfoOptional.orElse(null)
|
||||
if (documentInfo != null) {
|
||||
media.fileName = documentInfo.fileName
|
||||
|
||||
val extensionText: String = MediaUtil.getFileType(requireContext(), Optional.ofNullable(fileInfo.first), media.uri).orElse("")
|
||||
if (extensionText.length <= 3) {
|
||||
extension.text = extensionText
|
||||
extension.setTextAppearance(requireContext(), CoreUiR.style.Signal_Text_BodySmall)
|
||||
} else if (extensionText.length == 4) {
|
||||
extension.text = extensionText
|
||||
extension.setTextAppearance(requireContext(), CoreUiR.style.Signal_Text_Caption)
|
||||
name.text = documentInfo.fileName ?: getString(R.string.DocumentView_unnamed_file)
|
||||
size.text = documentInfo.fileSize.bytes.toUnitString()
|
||||
|
||||
if (documentInfo.extension.length <= 3) {
|
||||
extension.text = documentInfo.extension
|
||||
extension.setTextAppearance(requireContext(), CoreUiR.style.Signal_Text_BodySmall)
|
||||
} else if (documentInfo.extension.length == 4) {
|
||||
extension.text = documentInfo.extension
|
||||
extension.setTextAppearance(requireContext(), CoreUiR.style.Signal_Text_Caption)
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(requireContext(), R.string.ConversationActivity_sorry_there_was_an_error_setting_your_attachment, Toast.LENGTH_SHORT).show()
|
||||
requireActivity().finishAfterTransition()
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(requireContext(), R.string.ConversationActivity_sorry_there_was_an_error_setting_your_attachment, Toast.LENGTH_SHORT).show()
|
||||
requireActivity().finishAfterTransition()
|
||||
}
|
||||
|
||||
viewModel.loadDocumentInfo()
|
||||
}
|
||||
|
||||
override fun getUri(): Uri {
|
||||
@@ -85,57 +89,4 @@ class MediaSendDocumentFragment : Fragment(R.layout.mediasend_document_fragment)
|
||||
override fun restoreState(state: Any) = Unit
|
||||
|
||||
override fun notifyHidden() = Unit
|
||||
|
||||
private fun getFileInfo(): Pair<String?, Long>? {
|
||||
val fileInfo: Pair<String?, Long>
|
||||
try {
|
||||
if (PartAuthority.isLocalUri(uri)) {
|
||||
fileInfo = getManuallyCalculatedFileInfo(uri)
|
||||
} else {
|
||||
val result = getContentResolverFileInfo(uri)
|
||||
fileInfo = if ((result == null)) getManuallyCalculatedFileInfo(uri) else result
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Log.w(TAG, e)
|
||||
return null
|
||||
}
|
||||
|
||||
return fileInfo
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
private fun getManuallyCalculatedFileInfo(uri: Uri): Pair<String?, Long> {
|
||||
var fileName: String? = null
|
||||
var fileSize: Long? = null
|
||||
|
||||
if (PartAuthority.isLocalUri(uri)) {
|
||||
fileSize = PartAuthority.getAttachmentSize(requireContext(), uri)
|
||||
fileName = PartAuthority.getAttachmentFileName(requireContext(), uri)
|
||||
}
|
||||
if (fileSize == null) {
|
||||
fileSize = MediaUtil.getMediaSize(context, uri)
|
||||
}
|
||||
|
||||
return Pair(fileName, fileSize)
|
||||
}
|
||||
|
||||
private fun getContentResolverFileInfo(uri: Uri): Pair<String, Long>? {
|
||||
var cursor: Cursor? = null
|
||||
|
||||
try {
|
||||
cursor = requireContext().contentResolver.query(uri, null, null, null, null)
|
||||
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
val fileName = cursor.getString(cursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME))
|
||||
val fileSize = cursor.getLong(cursor.getColumnIndexOrThrow(OpenableColumns.SIZE))
|
||||
media.fileName = fileName
|
||||
|
||||
return Pair(fileName, fileSize)
|
||||
}
|
||||
} finally {
|
||||
cursor?.close()
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
package org.thoughtcrime.securesms.mediasend
|
||||
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import android.provider.OpenableColumns
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.signal.core.models.media.Media
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||
import org.thoughtcrime.securesms.mms.PartAuthority
|
||||
import org.thoughtcrime.securesms.util.MediaUtil
|
||||
import java.io.IOException
|
||||
import java.util.Optional
|
||||
|
||||
class MediaSendDocumentViewModel(private val media: Media) : ViewModel() {
|
||||
|
||||
private val internalDocumentInfo = MutableLiveData<Optional<DocumentInfo>>()
|
||||
val documentInfo: LiveData<Optional<DocumentInfo>> = internalDocumentInfo
|
||||
|
||||
fun loadDocumentInfo() {
|
||||
viewModelScope.launch {
|
||||
internalDocumentInfo.value = withContext(Dispatchers.IO) {
|
||||
Optional.ofNullable(computeDocumentInfo())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun computeDocumentInfo(): DocumentInfo? {
|
||||
val context = AppDependencies.application
|
||||
val fileInfo: Pair<String?, Long> = getFileInfo(context) ?: return null
|
||||
|
||||
val extensionText: String = MediaUtil.getFileType(context, Optional.ofNullable(fileInfo.first), media.uri).orElse("")
|
||||
|
||||
return DocumentInfo(fileInfo.first, fileInfo.second, extensionText)
|
||||
}
|
||||
|
||||
private fun getFileInfo(context: Context): Pair<String?, Long>? {
|
||||
val uri = media.uri
|
||||
return try {
|
||||
if (PartAuthority.isLocalUri(uri)) {
|
||||
getManuallyCalculatedFileInfo(context, uri)
|
||||
} else {
|
||||
getContentResolverFileInfo(context, uri) ?: getManuallyCalculatedFileInfo(context, uri)
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Log.w(TAG, e)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
private fun getManuallyCalculatedFileInfo(context: Context, uri: Uri): Pair<String?, Long> {
|
||||
var fileName: String? = null
|
||||
var fileSize: Long? = null
|
||||
|
||||
if (PartAuthority.isLocalUri(uri)) {
|
||||
fileSize = PartAuthority.getAttachmentSize(context, uri)
|
||||
fileName = PartAuthority.getAttachmentFileName(context, uri)
|
||||
}
|
||||
if (fileSize == null) {
|
||||
fileSize = MediaUtil.getMediaSize(context, uri)
|
||||
}
|
||||
|
||||
return Pair(fileName, fileSize)
|
||||
}
|
||||
|
||||
private fun getContentResolverFileInfo(context: Context, uri: Uri): Pair<String, Long>? {
|
||||
var cursor: Cursor? = null
|
||||
|
||||
try {
|
||||
cursor = context.contentResolver.query(uri, null, null, null, null)
|
||||
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
val fileName = cursor.getString(cursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME))
|
||||
val fileSize = cursor.getLong(cursor.getColumnIndexOrThrow(OpenableColumns.SIZE))
|
||||
|
||||
return Pair(fileName, fileSize)
|
||||
}
|
||||
} finally {
|
||||
cursor?.close()
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
data class DocumentInfo(val fileName: String?, val fileSize: Long, val extension: String)
|
||||
|
||||
class Factory(private val media: Media) : ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return requireNotNull(modelClass.cast(MediaSendDocumentViewModel(media)))
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = Log.tag(MediaSendDocumentViewModel::class.java)
|
||||
}
|
||||
}
|
||||
@@ -96,7 +96,7 @@ public final class Wallet {
|
||||
return SignalStore.payments().mobileCoinLatestBalance();
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@WorkerThread
|
||||
public @NonNull MobileCoinLedgerWrapper getCachedLedger() {
|
||||
return SignalStore.payments().mobileCoinLatestFullLedger();
|
||||
}
|
||||
|
||||
+20
-16
@@ -10,6 +10,7 @@ import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import org.signal.core.util.BidiUtil;
|
||||
import org.signal.core.util.StringUtil;
|
||||
import org.signal.core.util.concurrent.SignalExecutors;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.conversation.colors.AvatarColor;
|
||||
import org.thoughtcrime.securesms.groups.GroupId;
|
||||
@@ -143,24 +144,27 @@ class EditProfileViewModel extends ViewModel {
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] oldAvatar = originalAvatar.getValue();
|
||||
byte[] newAvatar = internalAvatar.getValue();
|
||||
String oldDisplayName = isGroup() ? originalDisplayName.getValue() : null;
|
||||
String oldDescription = isGroup() ? originalDescription : null;
|
||||
byte[] oldAvatar = originalAvatar.getValue();
|
||||
byte[] newAvatar = internalAvatar.getValue();
|
||||
String oldDisplayName = isGroup() ? originalDisplayName.getValue() : null;
|
||||
String oldDescription = isGroup() ? originalDescription : null;
|
||||
boolean isGroup = isGroup();
|
||||
|
||||
if (!isGroup() && SignalStore.phoneNumberPrivacy().getPhoneNumberDiscoverabilityMode() == PhoneNumberDiscoverabilityMode.UNDECIDED) {
|
||||
Log.i(TAG, "Phone number discoverability mode is still UNDECIDED. Setting to DISCOVERABLE.");
|
||||
SignalStore.phoneNumberPrivacy().setPhoneNumberDiscoverabilityMode(PhoneNumberDiscoverabilityMode.DISCOVERABLE);
|
||||
}
|
||||
SignalExecutors.BOUNDED.execute(() -> {
|
||||
if (!isGroup && SignalStore.phoneNumberPrivacy().getPhoneNumberDiscoverabilityMode() == PhoneNumberDiscoverabilityMode.UNDECIDED) {
|
||||
Log.i(TAG, "Phone number discoverability mode is still UNDECIDED. Setting to DISCOVERABLE.");
|
||||
SignalStore.phoneNumberPrivacy().setPhoneNumberDiscoverabilityMode(PhoneNumberDiscoverabilityMode.DISCOVERABLE);
|
||||
}
|
||||
|
||||
repository.uploadProfile(profileName,
|
||||
displayName,
|
||||
!Objects.equals(BidiUtil.stripBidiProtection(oldDisplayName), displayName),
|
||||
description,
|
||||
!Objects.equals(BidiUtil.stripBidiProtection(oldDescription), description),
|
||||
newAvatar,
|
||||
!Arrays.equals(oldAvatar, newAvatar),
|
||||
uploadResult::postValue);
|
||||
repository.uploadProfile(profileName,
|
||||
displayName,
|
||||
!Objects.equals(BidiUtil.stripBidiProtection(oldDisplayName), displayName),
|
||||
description,
|
||||
!Objects.equals(BidiUtil.stripBidiProtection(oldDescription), description),
|
||||
newAvatar,
|
||||
!Arrays.equals(oldAvatar, newAvatar),
|
||||
uploadResult::postValue);
|
||||
});
|
||||
}
|
||||
|
||||
static class Factory implements ViewModelProvider.Factory {
|
||||
|
||||
+5
-4
@@ -41,19 +41,20 @@ final class ShareableGroupLinkRepository {
|
||||
}
|
||||
|
||||
void toggleGroupLinkEnabled(@NonNull AsynchronousCallback.WorkerThread<Void, GroupChangeFailureReason> callback) {
|
||||
setGroupLinkEnabledState(toggleGroupLinkState(true, false), callback);
|
||||
setGroupLinkEnabledState(true, false, callback);
|
||||
}
|
||||
|
||||
void toggleGroupLinkApprovalRequired(@NonNull AsynchronousCallback.WorkerThread<Void, GroupChangeFailureReason> callback) {
|
||||
setGroupLinkEnabledState(toggleGroupLinkState(false, true), callback);
|
||||
setGroupLinkEnabledState(false, true, callback);
|
||||
}
|
||||
|
||||
private void setGroupLinkEnabledState(@NonNull GroupManager.GroupLinkState state,
|
||||
private void setGroupLinkEnabledState(boolean toggleEnabled,
|
||||
boolean toggleApprovalNeeded,
|
||||
@NonNull AsynchronousCallback.WorkerThread<Void, GroupChangeFailureReason> callback)
|
||||
{
|
||||
SignalExecutors.UNBOUNDED.execute(() -> {
|
||||
try {
|
||||
GroupManager.setGroupLinkEnabledState(context, groupId, state);
|
||||
GroupManager.setGroupLinkEnabledState(context, groupId, toggleGroupLinkState(toggleEnabled, toggleApprovalNeeded));
|
||||
callback.onComplete(null);
|
||||
} catch (GroupNotAMemberException | GroupChangeFailedException | GroupInsufficientRightsException | IOException | GroupChangeBusyException e) {
|
||||
callback.onError(GroupChangeFailureReason.fromException(e));
|
||||
|
||||
@@ -10,7 +10,6 @@ import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
|
||||
import androidx.annotation.AnyThread;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
@@ -84,7 +83,7 @@ public abstract class TimedEventManager<E> {
|
||||
* Schedules an alarm to call {@link #scheduleIfNecessary()} after the specified delay. You can
|
||||
* use {@link #setAlarm(Context, long, Class)} as a helper method.
|
||||
*/
|
||||
@AnyThread
|
||||
@WorkerThread
|
||||
protected abstract void scheduleAlarm(@NonNull Application application, E event, long delay);
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user