aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlookshe <github@lookshe.org>2016-03-25 20:04:37 +0100
committerlookshe <github@lookshe.org>2016-03-25 20:04:37 +0100
commit27c16b4b9acaad33b36145d63f6bfd7e04a3b3f1 (patch)
tree20740102fb6502dd6b130f51054a681275f44431
parent86d16b030b46aca24e6fab38e5d34beb503a6dc7 (diff)
parent46be514b4db1cb8c17037ac6cd307078e4794a12 (diff)
FS#169 - Merge Conversations 1.11.2 into Conversations+ dev
-rw-r--r--CHANGELOG.md5
-rw-r--r--build.gradle6
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/ConversationsPlusApplication.java2
-rw-r--r--src/main/java/eu/siacs/conversations/crypto/PgpEngine.java5
-rw-r--r--src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java6
-rw-r--r--src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java6
-rw-r--r--src/main/java/eu/siacs/conversations/persistance/FileBackend.java31
-rw-r--r--src/main/java/eu/siacs/conversations/services/XmppConnectionService.java3
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java2
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ConversationFragment.java28
-rw-r--r--src/main/java/eu/siacs/conversations/ui/SettingsActivity.java5
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java2
-rw-r--r--src/main/java/eu/siacs/conversations/ui/XmppActivity.java7
-rw-r--r--src/main/java/eu/siacs/conversations/utils/UIHelper.java9
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java10
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java4
-rw-r--r--src/main/res/menu/message_context.xml5
-rw-r--r--src/main/res/values/strings.xml1
18 files changed, 95 insertions, 42 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5a6bb27e..b9b3881c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
###Changelog
+####Version 1.11.2
+* only add image files to media scanner
+* allow to delete files
+* various bug fixes
+
####Version 1.11.1
* fixed some bugs when sharing files with Conversations
diff --git a/build.gradle b/build.gradle
index 190bf87c..bf6a8272 100644
--- a/build.gradle
+++ b/build.gradle
@@ -54,7 +54,7 @@ dependencies {
compile project(':libs:thedevstacklogcat')
// Android dependencies
- compile 'com.android.support:support-v13:21.0.3'
+ compile 'com.android.support:support-v13:23.2.0'
}
android {
@@ -64,8 +64,8 @@ android {
defaultConfig {
minSdkVersion 14
targetSdkVersion 23
- versionCode 133
- versionName "1.11.1"
+ versionCode 134
+ versionName "1.11.2"
archivesBaseName += "-$versionName"
}
diff --git a/src/main/java/de/thedevstack/conversationsplus/ConversationsPlusApplication.java b/src/main/java/de/thedevstack/conversationsplus/ConversationsPlusApplication.java
index 51637bc2..d902e8d4 100644
--- a/src/main/java/de/thedevstack/conversationsplus/ConversationsPlusApplication.java
+++ b/src/main/java/de/thedevstack/conversationsplus/ConversationsPlusApplication.java
@@ -9,6 +9,7 @@ import java.io.File;
import de.thedevstack.conversationsplus.utils.ImageUtil;
import eu.siacs.conversations.R;
+import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.utils.SerialSingleThreadExecutor;
/**
@@ -31,6 +32,7 @@ public class ConversationsPlusApplication extends Application {
ConversationsPlusApplication.instance = this;
ConversationsPlusPreferences.init(PreferenceManager.getDefaultSharedPreferences(getAppContext()));
ImageUtil.initBitmapCache();
+ FileBackend.createNoMedia();
}
/**
diff --git a/src/main/java/eu/siacs/conversations/crypto/PgpEngine.java b/src/main/java/eu/siacs/conversations/crypto/PgpEngine.java
index 0e79ea2c..56ca26da 100644
--- a/src/main/java/eu/siacs/conversations/crypto/PgpEngine.java
+++ b/src/main/java/eu/siacs/conversations/crypto/PgpEngine.java
@@ -2,7 +2,6 @@ package eu.siacs.conversations.crypto;
import android.app.PendingIntent;
import android.content.Intent;
-import android.net.Uri;
import org.openintents.openpgp.OpenPgpSignatureResult;
import org.openintents.openpgp.util.OpenPgpApi;
@@ -108,9 +107,7 @@ public class PgpEngine {
PgpEngine.this.mXmppConnectionService
.updateMessage(message);
inputFile.delete();
- Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
- intent.setData(Uri.fromFile(outputFile));
- mXmppConnectionService.sendBroadcast(intent);
+ FileBackend.updateMediaScanner(outputFile, mXmppConnectionService);
callback.success(message);
return;
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
diff --git a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java
index 7463a9a9..66687c3a 100644
--- a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java
+++ b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java
@@ -1,7 +1,5 @@
package eu.siacs.conversations.http;
-import android.content.Intent;
-import android.net.Uri;
import android.os.PowerManager;
import android.util.Log;
@@ -130,9 +128,7 @@ public class HttpDownloadConnection implements Transferable {
}
private void finish() {
- Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
- intent.setData(Uri.fromFile(file));
- mXmppConnectionService.sendBroadcast(intent);
+ FileBackend.updateMediaScanner(file, mXmppConnectionService);
message.setTransferable(null);
mHttpConnectionManager.finishConnection(this);
if (message.getEncryption() == Message.ENCRYPTION_PGP) {
diff --git a/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java
index 4842a218..1377e6ae 100644
--- a/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java
+++ b/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java
@@ -1,8 +1,6 @@
package eu.siacs.conversations.http;
import android.app.PendingIntent;
-import android.content.Intent;
-import android.net.Uri;
import android.os.PowerManager;
import android.util.Pair;
@@ -191,9 +189,7 @@ public class HttpUploadConnection implements Transferable {
mGetUrl = new URL(mGetUrl.toString() + "#" + CryptoHelper.bytesToHex(key));
}
MessageUtil.updateFileParams(message, mGetUrl);
- Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
- intent.setData(Uri.fromFile(file));
- mXmppConnectionService.sendBroadcast(intent);
+ FileBackend.updateMediaScanner(file, mXmppConnectionService);
message.setTransferable(null);
message.setCounterpart(message.getConversation().getJid().toBareJid());
if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
diff --git a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java
index 93b68809..6e766dd5 100644
--- a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java
+++ b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java
@@ -1,5 +1,6 @@
package eu.siacs.conversations.persistance;
+import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Environment;
@@ -25,10 +26,40 @@ import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.DownloadableFile;
import eu.siacs.conversations.entities.Message;
+import eu.siacs.conversations.services.XmppConnectionService;
public class FileBackend {
private static final SimpleDateFormat imageDateFormat = new SimpleDateFormat("yyyyMMdd_HHmmssSSS", Locale.US);
+ public static void createNoMedia() {
+ final File nomedia = new File(getConversationsFileDirectory()+".nomedia");
+ if (!nomedia.exists()) {
+ try {
+ nomedia.createNewFile();
+ } catch (Exception e) {
+ Log.d(Config.LOGTAG, "could not create nomedia file");
+ }
+ }
+ }
+
+ public static void updateMediaScanner(File file, XmppConnectionService xmppConnectionService) {
+ if (file.getAbsolutePath().startsWith(getConversationsImageDirectory())) {
+ Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
+ intent.setData(Uri.fromFile(file));
+ xmppConnectionService.sendBroadcast(intent);
+ }
+ }
+
+ public static boolean deleteFile(Message message, XmppConnectionService xmppConnectionService) {
+ File file = getFile(message);
+ if (file.delete()) {
+ updateMediaScanner(file, xmppConnectionService);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
public static DownloadableFile getFile(Message message) {
return getFile(message, true);
}
diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
index ce00fb0c..1f537172 100644
--- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
@@ -618,7 +618,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
private void resetAllAttemptCounts(boolean reallyAll) {
- Logging.d(Config.LOGTAG, "resetting all attepmt counts");
+ Logging.d(Config.LOGTAG, "resetting all attempt counts");
for (Account account : accounts) {
if (account.hasErrorStatus() || reallyAll) {
final XmppConnection connection = account.getXmppConnection();
@@ -2353,6 +2353,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
Thread thread = new Thread(connection);
connection.setInteractive(interactive);
+ connection.prepareNewConnection();
thread.start();
scheduleWakeUpCall(Config.CONNECT_DISCO_TIMEOUT, account.getUuid().hashCode());
} else {
diff --git a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
index 5bedc24d..b11564a9 100644
--- a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
@@ -457,7 +457,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
private void onOmemoKeyClicked(Account account, String fingerprint) {
final XmppAxolotlSession.Trust trust = account.getAxolotlService().getFingerprintTrust(fingerprint);
- if (trust != null && trust == XmppAxolotlSession.Trust.TRUSTED_X509) {
+ if (Config.X509_VERIFICATION && trust != null && trust == XmppAxolotlSession.Trust.TRUSTED_X509) {
X509Certificate x509Certificate = account.getAxolotlService().getFingerprintCertificate(fingerprint);
if (x509Certificate != null) {
showCertificateInformationDialog(CryptoHelper.extractCertificateInformation(x509Certificate));
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
index 3828e957..7a576c01 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
@@ -533,6 +533,9 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
final Message m = this.selectedMessage;
final Transferable t = m.getTransferable();
if (m.getType() != Message.TYPE_STATUS) {
+ final boolean treatAsFile = m.getType() != Message.TYPE_TEXT
+ && m.getType() != Message.TYPE_PRIVATE
+ && t == null;
activity.getMenuInflater().inflate(R.menu.message_context, menu);
menu.setHeaderTitle(R.string.message_options);
MenuItem copyText = menu.findItem(R.id.copy_text);
@@ -542,8 +545,8 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
MenuItem copyUrl = menu.findItem(R.id.copy_url);
MenuItem downloadFile = menu.findItem(R.id.download_file);
MenuItem cancelTransmission = menu.findItem(R.id.cancel_transmission);
- if ((m.getType() == Message.TYPE_TEXT || m.getType() == Message.TYPE_PRIVATE)
- && t == null
+ MenuItem deleteFile = menu.findItem(R.id.delete_file);
+ if (!treatAsFile
&& !GeoHelper.isGeoUri(m.getBody())
&& m.treatAsDownloadable() != Message.Decision.MUST) {
copyText.setVisible(true);
@@ -551,11 +554,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
if (m.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) {
retryDecryption.setVisible(true);
}
-
- if ((m.getType() != Message.TYPE_TEXT
- && m.getType() != Message.TYPE_PRIVATE
- && t == null)
- || (GeoHelper.isGeoUri(m.getBody()))) {
+ if (treatAsFile || (GeoHelper.isGeoUri(m.getBody()))) {
shareWith.setVisible(true);
}
if (m.getStatus() == Message.STATUS_SEND_FAILED) {
@@ -577,6 +576,10 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
|| m.getStatus() == Message.STATUS_OFFERED))) {
cancelTransmission.setVisible(true);
}
+ if (treatAsFile) {
+ deleteFile.setVisible(true);
+ deleteFile.setTitle(activity.getString(R.string.delete_x_file,UIHelper.getFileDescriptionString(activity, m)));
+ }
}
}
@@ -607,6 +610,9 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
case R.id.retry_decryption:
retryDecryption(selectedMessage);
return true;
+ case R.id.delete_file:
+ deleteFile(selectedMessage);
+ return true;
default:
return super.onContextItemSelected(item);
}
@@ -644,12 +650,20 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
}
}
+ private void deleteFile(Message message) {
+ if (FileBackend.deleteFile(message, activity.xmppConnectionService)) {
+ message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_DELETED));
+ activity.xmppConnectionService.updateConversationUi();
+ }
+ }
+
private void resendMessage(Message message) {
if (message.getType() == Message.TYPE_FILE || message.getType() == Message.TYPE_IMAGE) {
DownloadableFile file = FileBackend.getFile(message);
if (!file.exists()) {
Toast.makeText(activity, R.string.file_deleted, Toast.LENGTH_SHORT).show();
message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_DELETED));
+ activity.xmppConnectionService.updateConversationUi();
return;
}
}
diff --git a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java
index c0bd162e..5b1978c4 100644
--- a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java
@@ -30,6 +30,7 @@ import de.tzur.conversations.Settings;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.services.ExportLogsService;
import eu.siacs.conversations.xmpp.XmppConnection;
import github.ankushsachdeva.emojicon.EmojiconHandler;
@@ -185,7 +186,9 @@ public class SettingsActivity extends XmppActivity implements
reconnectAccounts();
} else if ("parse_emoticons".equals(name)) {
EmojiconHandler.setParseEmoticons(Settings.PARSE_EMOTICONS);
- }
+ } else if ("file_transfer_folder".equals(name)) {
+ FileBackend.createNoMedia();
+ }
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java
index cc2806f9..91dd32d9 100644
--- a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java
@@ -191,7 +191,7 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
if (Intent.ACTION_SEND.equals(action)) {
final String text = intent.getStringExtra(Intent.EXTRA_TEXT);
final Uri uri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
- if (type != null && uri != null && text == null) {
+ if (type != null && uri != null && (text == null || !type.equals("text/plain"))) {
this.share.uris.clear();
this.share.uris.add(uri);
this.share.image = type.startsWith("image/") || isImage(uri);
diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
index 8923ef31..2e2700e9 100644
--- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
@@ -739,14 +739,15 @@ public abstract class XmppActivity extends Activity {
view.setOnLongClickListener(purge);
key.setOnLongClickListener(purge);
keyType.setOnLongClickListener(purge);
- boolean x509 = trust == XmppAxolotlSession.Trust.TRUSTED_X509 || trust == XmppAxolotlSession.Trust.INACTIVE_TRUSTED_X509;
+ boolean x509 = Config.X509_VERIFICATION
+ && (trust == XmppAxolotlSession.Trust.TRUSTED_X509 || trust == XmppAxolotlSession.Trust.INACTIVE_TRUSTED_X509);
switch (trust) {
case UNTRUSTED:
case TRUSTED:
case TRUSTED_X509:
trustToggle.setChecked(trust.trusted());
- trustToggle.setEnabled(trust != XmppAxolotlSession.Trust.TRUSTED_X509);
- if (trust == XmppAxolotlSession.Trust.TRUSTED_X509) {
+ trustToggle.setEnabled(!Config.X509_VERIFICATION || trust != XmppAxolotlSession.Trust.TRUSTED_X509);
+ if (Config.X509_VERIFICATION && trust == XmppAxolotlSession.Trust.TRUSTED_X509) {
trustToggle.setOnClickListener(null);
}
key.setTextColor(getPrimaryTextColor());
diff --git a/src/main/java/eu/siacs/conversations/utils/UIHelper.java b/src/main/java/eu/siacs/conversations/utils/UIHelper.java
index b714b895..5e4b4acd 100644
--- a/src/main/java/eu/siacs/conversations/utils/UIHelper.java
+++ b/src/main/java/eu/siacs/conversations/utils/UIHelper.java
@@ -220,9 +220,10 @@ public class UIHelper {
}
public static String getMessageDisplayName(final Message message) {
+ final Conversation conversation = message.getConversation();
if (message.getStatus() == Message.STATUS_RECEIVED) {
final Contact contact = message.getContact();
- if (message.getConversation().getMode() == Conversation.MODE_MULTI) {
+ if (conversation.getMode() == Conversation.MODE_MULTI) {
if (contact != null) {
return contact.getDisplayName();
} else {
@@ -232,10 +233,10 @@ public class UIHelper {
return contact != null ? contact.getDisplayName() : "";
}
} else {
- if (message.getConversation().getMode() == Conversation.MODE_MULTI) {
- return getDisplayedMucCounterpart(message.getConversation().getJid());
+ if (conversation.getMode() == Conversation.MODE_MULTI) {
+ return conversation.getMucOptions().getSelf().getName();
} else {
- final Jid jid = message.getConversation().getAccount().getJid();
+ final Jid jid = conversation.getAccount().getJid();
return jid.hasLocalpart() ? jid.getLocalpart() : jid.toDomainJid().toString();
}
}
diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
index 9d167edd..acdf5652 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
@@ -222,12 +222,16 @@ public class XmppConnection implements Runnable {
}
}
+ public void prepareNewConnection() {
+ this.lastConnect = SystemClock.elapsedRealtime();
+ this.lastPingSent = SystemClock.elapsedRealtime();
+ this.lastDiscoStarted = Long.MAX_VALUE;
+ this.changeStatus(Account.State.CONNECTING);
+ }
+
protected void connect() {
Logging.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": connecting");
features.encryptionEnabled = false;
- lastConnect = SystemClock.elapsedRealtime();
- lastPingSent = SystemClock.elapsedRealtime();
- lastDiscoStarted = Long.MAX_VALUE;
this.attempt++;
switch (account.getJid().getDomainpart()) {
case "chat.facebook.com":
diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java
index 8185c8e1..22f5dca9 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java
@@ -115,9 +115,7 @@ public class JingleConnection implements Transferable {
}
Logging.d(Config.LOGTAG,"successfully transmitted file:" + file.getAbsolutePath()+" ("+file.getSha1Sum()+")");
if (message.getEncryption() != Message.ENCRYPTION_PGP) {
- Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
- intent.setData(Uri.fromFile(file));
- mXmppConnectionService.sendBroadcast(intent);
+ FileBackend.updateMediaScanner(file, mXmppConnectionService);
} else {
account.getPgpDecryptionService().add(message);
}
diff --git a/src/main/res/menu/message_context.xml b/src/main/res/menu/message_context.xml
index 292a4938..0c7d8eef 100644
--- a/src/main/res/menu/message_context.xml
+++ b/src/main/res/menu/message_context.xml
@@ -32,5 +32,8 @@
android:id="@+id/cancel_transmission"
android:title="@string/cancel_transmission"
android:visible="false"/>
-
+ <item
+ android:id="@+id/delete_file"
+ android:title="@string/delete_x_file"
+ android:visible="false"/>
</menu> \ No newline at end of file
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 49207841..3e939114 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -399,6 +399,7 @@
<string name="choose_file">Choose file</string>
<string name="receiving_x_file">Receiving %1$s (%2$d%% completed)</string>
<string name="download_x_file">Download %s</string>
+ <string name="delete_x_file">Delete %s</string>
<string name="file">file</string>
<string name="open_x_file">Open %s</string>
<string name="sending_file">sending (%1$d%% completed)</string>