Renamed Send

This commit is contained in:
M66B 2022-07-31 21:41:40 +02:00
parent b5a987c6c7
commit 817088779d
8 changed files with 82 additions and 82 deletions

12
FAQ.md
View File

@ -385,7 +385,7 @@ Fonts, sizes, colors, etc should be material design whenever possible.
* [(180) How do I use LanguageTool?](#user-content-faq180) * [(180) How do I use LanguageTool?](#user-content-faq180)
* [(181) How do I use VirusTotal?](#user-content-faq181) * [(181) How do I use VirusTotal?](#user-content-faq181)
* [(182) How can I select how a link should be opened?](#user-content-faq182) * [(182) How can I select how a link should be opened?](#user-content-faq182)
* [(183) How do I use FFSend?](#user-content-faq183) * [(183) How do I use Send?](#user-content-faq183)
[I have another question.](#user-content-get-support) [I have another question.](#user-content-get-support)
@ -4895,19 +4895,19 @@ Please see [this FAQ](#user-content-faq35) on why you should be careful when ope
<br /> <br />
<a name="faq183"></a> <a name="faq183"></a>
**(183) How do I use FFSend?** **(183) How do I use Send?**
[FFSend](https://github.com/timvisee/send) is designed as temporary encrypted file storage. [Send](https://github.com/timvisee/send) is designed as temporary encrypted file storage.
Only people with a link to a file can download and decrypt a file. Only people with a link to a file can download and decrypt a file.
FFSend integration needs to be enabled in the miscellaneous settings. Send integration needs to be enabled in the miscellaneous settings.
Optionally, you can change the host address of the FFSend server. Optionally, you can change the host address of the Send server.
Please [see here](https://github.com/timvisee/send-instances) for a list of public instances. Please [see here](https://github.com/timvisee/send-instances) for a list of public instances.
To upload a file and insert a link, you can use the insert link button in the message editor. To upload a file and insert a link, you can use the insert link button in the message editor.
FFSend is only available in non-Play Store versions of the app (since version 1.1947). Send is only available in non-Play Store versions of the app (since version 1.1947).
<br /> <br />

View File

@ -4,7 +4,7 @@ import androidx.documentfile.provider.DocumentFile;
import java.io.InputStream; import java.io.InputStream;
public class FFSend { public class Send {
static final int FF_DEFAULT_DLIMIT = 0; static final int FF_DEFAULT_DLIMIT = 0;
static final int FF_DEFAULT_TLIMIT = 0; static final int FF_DEFAULT_TLIMIT = 0;
static final String FF_DEFAULT_SERVER = ""; static final String FF_DEFAULT_SERVER = "";

View File

@ -39,7 +39,7 @@ import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;
public class FFSend { public class Send {
// https://datatracker.ietf.org/doc/html/rfc8188 // https://datatracker.ietf.org/doc/html/rfc8188
// https://github.com/nneonneo/ffsend/blob/master/ffsend.py // https://github.com/nneonneo/ffsend/blob/master/ffsend.py
@ -50,8 +50,8 @@ public class FFSend {
--data '{"owner_token": "..."}' --data '{"owner_token": "..."}'
*/ */
static final int FF_DEFAULT_DLIMIT = 10; static final int DEFAULT_DLIMIT = 10;
static final int FF_DEFAULT_TLIMIT = 24; // hours static final int DEFAULT_TLIMIT = 24; // hours
static final String FF_DEFAULT_SERVER = "https://send.vis.ee/"; static final String FF_DEFAULT_SERVER = "https://send.vis.ee/";
static final String FF_INSTANCES = "https://github.com/timvisee/send-instances/"; static final String FF_INSTANCES = "https://github.com/timvisee/send-instances/";
@ -76,31 +76,31 @@ public class FFSend {
ws.addListener(new WebSocketAdapter() { ws.addListener(new WebSocketAdapter() {
@Override @Override
public void onTextMessage(WebSocket ws, String text) throws Exception { public void onTextMessage(WebSocket ws, String text) throws Exception {
Log.i("FFSend text message=" + text); Log.i("Send text message=" + text);
queue.add(text); queue.add(text);
sem.release(); sem.release();
} }
}); });
Log.i("FFSend connect"); Log.i("Send connect");
ws.connect(); ws.connect();
try { try {
Log.i("FFSend upload=" + jupload); Log.i("Send upload=" + jupload);
ws.sendText(jupload.toString()); ws.sendText(jupload.toString());
Log.i("FFSend wait reply"); Log.i("Send wait reply");
sem.tryAcquire(FF_TIMEOUT, TimeUnit.MILLISECONDS); sem.tryAcquire(FF_TIMEOUT, TimeUnit.MILLISECONDS);
JSONObject jreply = new JSONObject(queue.remove(0)); JSONObject jreply = new JSONObject(queue.remove(0));
Log.i("FFSend reply=" + jreply); Log.i("Send reply=" + jreply);
if (jreply.has("error")) if (jreply.has("error"))
throw new IOException("Error: " + jreply.getString("error")); throw new IOException("Error: " + jreply.getString("error"));
result = jreply.getString("url") + result = jreply.getString("url") +
"#" + Base64.encodeToString(secret, Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP); "#" + Base64.encodeToString(secret, Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP);
Log.i("FFSend url=" + result); Log.i("Send url=" + result);
// The record sequence number (SEQ) is a 96-bit unsigned integer in network byte order that starts at zero. // The record sequence number (SEQ) is a 96-bit unsigned integer in network byte order that starts at zero.
// network byte order = transmitting the most significant byte first // network byte order = transmitting the most significant byte first
@ -120,7 +120,7 @@ public class FFSend {
// idlen = 0 // idlen = 0
// keyid = "" // keyid = ""
Log.i("FFSend header=" + Helper.hex(header)); Log.i("Send header=" + Helper.hex(header));
ws.sendBinary(header); ws.sendBinary(header);
// https://datatracker.ietf.org/doc/html/rfc8188#section-2.2 // https://datatracker.ietf.org/doc/html/rfc8188#section-2.2
@ -141,7 +141,7 @@ public class FFSend {
hkdf = new HKDFBytesGenerator(new SHA256Digest()); hkdf = new HKDFBytesGenerator(new SHA256Digest());
hkdf.init(new HKDFParameters(secret /* ikm */, salt, "Content-Encoding: nonce\0".getBytes())); hkdf.init(new HKDFParameters(secret /* ikm */, salt, "Content-Encoding: nonce\0".getBytes()));
hkdf.generateBytes(nonce_base /* okm */, 0, nonce_base.length); hkdf.generateBytes(nonce_base /* okm */, 0, nonce_base.length);
Log.i("FFSend nonce base=" + Helper.hex(nonce_base)); Log.i("Send nonce base=" + Helper.hex(nonce_base));
// TODO zero length files // TODO zero length files
int len; int len;
@ -149,7 +149,7 @@ public class FFSend {
long fileSize = dfile.length(); long fileSize = dfile.length();
// content any length up to rs-17 octets // content any length up to rs-17 octets
while ((len = is.read(buffer, 0, buffer.length - 17)) > 0) { while ((len = is.read(buffer, 0, buffer.length - 17)) > 0) {
Log.i("FFSend read=" + len); Log.i("Send read=" + len);
// add a delimiter octet (0x01 or 0x02) // add a delimiter octet (0x01 or 0x02)
// then 0x00-valued octets to rs-16 (or less on the last record) // then 0x00-valued octets to rs-16 (or less on the last record)
@ -163,12 +163,12 @@ public class FFSend {
while (len < buffer.length - 17) while (len < buffer.length - 17)
buffer[len++] = 0x00; buffer[len++] = 0x00;
} }
Log.i("FFSend record len=" + len + " size=" + size + "/" + fileSize); Log.i("Send record len=" + len + " size=" + size + "/" + fileSize);
byte[] nonce = Arrays.copyOf(nonce_base, nonce_base.length); byte[] nonce = Arrays.copyOf(nonce_base, nonce_base.length);
ByteBuffer xor = ByteBuffer.wrap(nonce); ByteBuffer xor = ByteBuffer.wrap(nonce);
xor.putInt(nonce.length - 4, xor.getInt(nonce.length - 4) ^ seq); xor.putInt(nonce.length - 4, xor.getInt(nonce.length - 4) ^ seq);
Log.i("FFSend seq=" + seq + " nonce=" + Helper.hex(nonce)); Log.i("Send seq=" + seq + " nonce=" + Helper.hex(nonce));
// encrypt with AEAD_AES_128_GCM; final size is rs; the last record can be smaller // encrypt with AEAD_AES_128_GCM; final size is rs; the last record can be smaller
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
@ -176,20 +176,20 @@ public class FFSend {
new SecretKeySpec(cek, "AES"), new SecretKeySpec(cek, "AES"),
new GCMParameterSpec(16 * 8, nonce)); new GCMParameterSpec(16 * 8, nonce));
byte[] message = cipher.doFinal(buffer, 0, len); byte[] message = cipher.doFinal(buffer, 0, len);
Log.i("FFSend message len=" + message.length); Log.i("Send message len=" + message.length);
ws.sendBinary(message); ws.sendBinary(message);
seq++; seq++;
} }
Log.i("FFSend EOF size=" + size); Log.i("Send EOF size=" + size);
ws.sendBinary(new byte[]{0}, true); ws.sendBinary(new byte[]{0}, true);
Log.i("FFSend wait confirm"); Log.i("Send wait confirm");
sem.tryAcquire(FF_TIMEOUT, TimeUnit.MILLISECONDS); sem.tryAcquire(FF_TIMEOUT, TimeUnit.MILLISECONDS);
JSONObject jconfirm = new JSONObject(queue.remove(0)); JSONObject jconfirm = new JSONObject(queue.remove(0));
Log.i("FFSend confirm=" + jconfirm); Log.i("Send confirm=" + jconfirm);
if (!jconfirm.getBoolean("ok")) if (!jconfirm.getBoolean("ok"))
throw new FileNotFoundException(); throw new FileNotFoundException();
} finally { } finally {
@ -225,7 +225,7 @@ public class FFSend {
jmeta.put("type", mimeType); jmeta.put("type", mimeType);
jmeta.put("manifest", jmanifest); jmeta.put("manifest", jmanifest);
Log.i("FFSend meta=" + jmeta); Log.i("Send meta=" + jmeta);
byte[] auth_key = new byte[64]; byte[] auth_key = new byte[64];
HKDFBytesGenerator hkdf = new HKDFBytesGenerator(new SHA256Digest()); HKDFBytesGenerator hkdf = new HKDFBytesGenerator(new SHA256Digest());

View File

@ -71,7 +71,7 @@ public class FragmentDialogInsertLink extends FragmentDialogBase {
private static final int METADATA_CONNECT_TIMEOUT = 10 * 1000; // milliseconds private static final int METADATA_CONNECT_TIMEOUT = 10 * 1000; // milliseconds
private static final int METADATA_READ_TIMEOUT = 15 * 1000; // milliseconds private static final int METADATA_READ_TIMEOUT = 15 * 1000; // milliseconds
private static final int REQUEST_FFSEND = 1; private static final int REQUEST_SEND = 1;
@Override @Override
public void onSaveInstanceState(@NonNull Bundle outState) { public void onSaveInstanceState(@NonNull Bundle outState) {
@ -103,7 +103,7 @@ public class FragmentDialogInsertLink extends FragmentDialogBase {
Group grpUpload = view.findViewById(R.id.grpUpload); Group grpUpload = view.findViewById(R.id.grpUpload);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean ffsend_enabled = prefs.getBoolean("ffsend_enabled", false); boolean send_enabled = prefs.getBoolean("send_enabled", false);
etLink.addTextChangedListener(new TextWatcher() { etLink.addTextChangedListener(new TextWatcher() {
@Override @Override
@ -257,7 +257,7 @@ public class FragmentDialogInsertLink extends FragmentDialogBase {
intent.addCategory(Intent.CATEGORY_OPENABLE); intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setType("*/*"); intent.setType("*/*");
startActivityForResult(Helper.getChooser(getContext(), intent), REQUEST_FFSEND); startActivityForResult(Helper.getChooser(getContext(), intent), REQUEST_SEND);
} }
}); });
@ -265,7 +265,7 @@ public class FragmentDialogInsertLink extends FragmentDialogBase {
@Override @Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
progress++; progress++;
tvDLimit.setText(getString(R.string.title_style_link_ffsend_dlimit, Integer.toString(progress))); tvDLimit.setText(getString(R.string.title_style_link_send_dlimit, Integer.toString(progress)));
} }
@Override @Override
@ -285,11 +285,11 @@ public class FragmentDialogInsertLink extends FragmentDialogBase {
progress++; progress++;
if (progress < 24) if (progress < 24)
tvTLimit.setText(getString(R.string.title_style_link_ffsend_tlimit, tvTLimit.setText(getString(R.string.title_style_link_send_tlimit,
getResources().getQuantityString(R.plurals.title_hours, progress, progress))); getResources().getQuantityString(R.plurals.title_hours, progress, progress)));
else { else {
progress = (progress - 24 + 1); progress = (progress - 24 + 1);
tvTLimit.setText(getString(R.string.title_style_link_ffsend_tlimit, tvTLimit.setText(getString(R.string.title_style_link_send_tlimit,
getResources().getQuantityString(R.plurals.title_days, progress, progress))); getResources().getQuantityString(R.plurals.title_days, progress, progress)));
} }
} }
@ -314,12 +314,12 @@ public class FragmentDialogInsertLink extends FragmentDialogBase {
etTitle.setText(savedInstanceState.getString("fair:text")); etTitle.setText(savedInstanceState.getString("fair:text"));
} }
sbDLimit.setProgress(FFSend.FF_DEFAULT_DLIMIT - 1); sbDLimit.setProgress(Send.DEFAULT_DLIMIT - 1);
sbTLimit.setProgress(FFSend.FF_DEFAULT_TLIMIT - 1); sbTLimit.setProgress(Send.DEFAULT_TLIMIT - 1);
pbWait.setVisibility(View.GONE); pbWait.setVisibility(View.GONE);
pbUpload.setVisibility(View.GONE); pbUpload.setVisibility(View.GONE);
grpUpload.setVisibility(ffsend_enabled && !BuildConfig.PLAY_STORE_RELEASE grpUpload.setVisibility(send_enabled && !BuildConfig.PLAY_STORE_RELEASE
? View.VISIBLE : View.GONE); ? View.VISIBLE : View.GONE);
return new AlertDialog.Builder(context) return new AlertDialog.Builder(context)
@ -348,9 +348,9 @@ public class FragmentDialogInsertLink extends FragmentDialogBase {
try { try {
switch (requestCode) { switch (requestCode) {
case REQUEST_FFSEND: case REQUEST_SEND:
if (resultCode == RESULT_OK && data != null) if (resultCode == RESULT_OK && data != null)
onFFSend(data.getData()); onSend(data.getData());
break; break;
} }
} catch (Throwable ex) { } catch (Throwable ex) {
@ -358,7 +358,7 @@ public class FragmentDialogInsertLink extends FragmentDialogBase {
} }
} }
private void onFFSend(Uri uri) { private void onSend(Uri uri) {
int dlimit = sbDLimit.getProgress() + 1; int dlimit = sbDLimit.getProgress() + 1;
int tlimit = sbTLimit.getProgress() + 1; int tlimit = sbTLimit.getProgress() + 1;
@ -404,26 +404,26 @@ public class FragmentDialogInsertLink extends FragmentDialogBase {
throw new FileNotFoundException("dfile"); throw new FileNotFoundException("dfile");
if (dlimit == 0) if (dlimit == 0)
dlimit = FFSend.FF_DEFAULT_DLIMIT; dlimit = Send.DEFAULT_DLIMIT;
if (tlimit == 0) if (tlimit == 0)
tlimit = FFSend.FF_DEFAULT_TLIMIT; tlimit = Send.DEFAULT_TLIMIT;
Log.i("FFSend uri=" + uri + " dlimit=" + dlimit + " tlimit=" + tlimit); Log.i("Send uri=" + uri + " dlimit=" + dlimit + " tlimit=" + tlimit);
args.putString("title", dfile.getName()); args.putString("title", dfile.getName());
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String ffsend_host = prefs.getString("ffsend_host", FFSend.FF_DEFAULT_SERVER); String send_host = prefs.getString("send_host", Send.FF_DEFAULT_SERVER);
ContentResolver resolver = context.getContentResolver(); ContentResolver resolver = context.getContentResolver();
try (InputStream is = resolver.openInputStream(uri)) { try (InputStream is = resolver.openInputStream(uri)) {
return FFSend.upload(is, dfile, dlimit, tlimit * 60 * 60, ffsend_host); return Send.upload(is, dfile, dlimit, tlimit * 60 * 60, send_host);
} }
} }
@Override @Override
protected void onExecuted(Bundle args, String ffsend) { protected void onExecuted(Bundle args, String link) {
etLink.setText(ffsend); etLink.setText(link);
etTitle.setText(args.getString("title")); etTitle.setText(args.getString("title"));
} }
@ -431,7 +431,7 @@ public class FragmentDialogInsertLink extends FragmentDialogBase {
protected void onException(Bundle args, Throwable ex) { protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(getParentFragmentManager(), ex); Log.unexpectedError(getParentFragmentManager(), ex);
} }
}.execute(this, args, "ffsend"); }.execute(this, args, "send");
} }
private static class OpenGraph { private static class OpenGraph {

View File

@ -126,9 +126,9 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
private TextView tvVirusTotalPrivacy; private TextView tvVirusTotalPrivacy;
private EditText etVirusTotal; private EditText etVirusTotal;
private ImageButton ibVirusTotal; private ImageButton ibVirusTotal;
private SwitchCompat swFFSend; private SwitchCompat swSend;
private EditText etFFSend; private EditText etSend;
private ImageButton ibFFSend; private ImageButton ibSend;
private SwitchCompat swUpdates; private SwitchCompat swUpdates;
private ImageButton ibChannelUpdated; private ImageButton ibChannelUpdated;
private SwitchCompat swCheckWeekly; private SwitchCompat swCheckWeekly;
@ -218,7 +218,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
private TextView tvPermissions; private TextView tvPermissions;
private Group grpVirusTotal; private Group grpVirusTotal;
private Group grpFFSend; private Group grpSend;
private Group grpUpdates; private Group grpUpdates;
private Group grpTest; private Group grpTest;
private CardView cardDebug; private CardView cardDebug;
@ -230,7 +230,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
private final static String[] RESET_OPTIONS = new String[]{ private final static String[] RESET_OPTIONS = new String[]{
"sort_answers", "shortcuts", "fts", "sort_answers", "shortcuts", "fts",
"classification", "class_min_probability", "class_min_difference", "classification", "class_min_probability", "class_min_difference",
"language", "lt_enabled", "deepl_enabled", "vt_enabled", "vt_apikey", "ffsend_enabled", "ffsend_host", "language", "lt_enabled", "deepl_enabled", "vt_enabled", "vt_apikey", "send_enabled", "send_host",
"updates", "weekly", "show_changelog", "updates", "weekly", "show_changelog",
"crash_reports", "cleanup_attachments", "crash_reports", "cleanup_attachments",
"watchdog", "experiments", "main_log", "protocol", "log_level", "debug", "leak_canary", "watchdog", "experiments", "main_log", "protocol", "log_level", "debug", "leak_canary",
@ -321,9 +321,9 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
tvVirusTotalPrivacy = view.findViewById(R.id.tvVirusTotalPrivacy); tvVirusTotalPrivacy = view.findViewById(R.id.tvVirusTotalPrivacy);
etVirusTotal = view.findViewById(R.id.etVirusTotal); etVirusTotal = view.findViewById(R.id.etVirusTotal);
ibVirusTotal = view.findViewById(R.id.ibVirusTotal); ibVirusTotal = view.findViewById(R.id.ibVirusTotal);
swFFSend = view.findViewById(R.id.swFFSend); swSend = view.findViewById(R.id.swSend);
etFFSend = view.findViewById(R.id.etFFSend); etSend = view.findViewById(R.id.etSend);
ibFFSend = view.findViewById(R.id.ibFFSend); ibSend = view.findViewById(R.id.ibSend);
swUpdates = view.findViewById(R.id.swUpdates); swUpdates = view.findViewById(R.id.swUpdates);
ibChannelUpdated = view.findViewById(R.id.ibChannelUpdated); ibChannelUpdated = view.findViewById(R.id.ibChannelUpdated);
swCheckWeekly = view.findViewById(R.id.swWeekly); swCheckWeekly = view.findViewById(R.id.swWeekly);
@ -413,7 +413,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
tvPermissions = view.findViewById(R.id.tvPermissions); tvPermissions = view.findViewById(R.id.tvPermissions);
grpVirusTotal = view.findViewById(R.id.grpVirusTotal); grpVirusTotal = view.findViewById(R.id.grpVirusTotal);
grpFFSend = view.findViewById(R.id.grpFFSend); grpSend = view.findViewById(R.id.grpSend);
grpUpdates = view.findViewById(R.id.grpUpdates); grpUpdates = view.findViewById(R.id.grpUpdates);
grpTest = view.findViewById(R.id.grpTest); grpTest = view.findViewById(R.id.grpTest);
cardDebug = view.findViewById(R.id.cardDebug); cardDebug = view.findViewById(R.id.cardDebug);
@ -697,15 +697,15 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
} }
}); });
swFFSend.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { swSend.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override @Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
prefs.edit().putBoolean("ffsend_enabled", checked).apply(); prefs.edit().putBoolean("send_enabled", checked).apply();
} }
}); });
etFFSend.setHint(FFSend.FF_DEFAULT_SERVER); etSend.setHint(Send.FF_DEFAULT_SERVER);
etFFSend.addTextChangedListener(new TextWatcher() { etSend.addTextChangedListener(new TextWatcher() {
@Override @Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) { public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// Do nothing // Do nothing
@ -720,13 +720,13 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
public void afterTextChanged(Editable s) { public void afterTextChanged(Editable s) {
String apikey = s.toString().trim(); String apikey = s.toString().trim();
if (TextUtils.isEmpty(apikey)) if (TextUtils.isEmpty(apikey))
prefs.edit().remove("ffsend_host").apply(); prefs.edit().remove("send_host").apply();
else else
prefs.edit().putString("ffsend_host", apikey).apply(); prefs.edit().putString("send_host", apikey).apply();
} }
}); });
ibFFSend.setOnClickListener(new View.OnClickListener() { ibSend.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
Helper.viewFAQ(v.getContext(), 183); Helper.viewFAQ(v.getContext(), 183);
@ -1676,7 +1676,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
}); });
grpVirusTotal.setVisibility(BuildConfig.PLAY_STORE_RELEASE ? View.GONE : View.VISIBLE); grpVirusTotal.setVisibility(BuildConfig.PLAY_STORE_RELEASE ? View.GONE : View.VISIBLE);
grpFFSend.setVisibility(BuildConfig.PLAY_STORE_RELEASE ? View.GONE : View.VISIBLE); grpSend.setVisibility(BuildConfig.PLAY_STORE_RELEASE ? View.GONE : View.VISIBLE);
grpUpdates.setVisibility(!BuildConfig.DEBUG && grpUpdates.setVisibility(!BuildConfig.DEBUG &&
(Helper.isPlayStoreInstall() || !Helper.hasValidFingerprint(getContext())) (Helper.isPlayStoreInstall() || !Helper.hasValidFingerprint(getContext()))
@ -1751,7 +1751,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
if ("last_cleanup".equals(key)) if ("last_cleanup".equals(key))
setLastCleanup(prefs.getLong(key, -1)); setLastCleanup(prefs.getLong(key, -1));
if ("vt_apikey".equals(key) || "ffsend_host".equals(key)) if ("vt_apikey".equals(key) || "send_host".equals(key))
return; return;
setOptions(); setOptions();
@ -1898,8 +1898,8 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
swDeepL.setChecked(prefs.getBoolean("deepl_enabled", false)); swDeepL.setChecked(prefs.getBoolean("deepl_enabled", false));
swVirusTotal.setChecked(prefs.getBoolean("vt_enabled", false)); swVirusTotal.setChecked(prefs.getBoolean("vt_enabled", false));
etVirusTotal.setText(prefs.getString("vt_apikey", null)); etVirusTotal.setText(prefs.getString("vt_apikey", null));
swFFSend.setChecked(prefs.getBoolean("ffsend_enabled", false)); swSend.setChecked(prefs.getBoolean("send_enabled", false));
etFFSend.setText(prefs.getString("ffsend_host", null)); etSend.setText(prefs.getString("send_host", null));
swUpdates.setChecked(prefs.getBoolean("updates", true)); swUpdates.setChecked(prefs.getBoolean("updates", true));
swCheckWeekly.setChecked(prefs.getBoolean("weekly", Helper.hasPlayStore(getContext()))); swCheckWeekly.setChecked(prefs.getBoolean("weekly", Helper.hasPlayStore(getContext())));
swCheckWeekly.setEnabled(swUpdates.isChecked()); swCheckWeekly.setEnabled(swUpdates.isChecked());

View File

@ -120,7 +120,7 @@
android:layout_marginTop="12dp" android:layout_marginTop="12dp"
android:drawableEnd="@drawable/twotone_file_upload_24" android:drawableEnd="@drawable/twotone_file_upload_24"
android:drawablePadding="6dp" android:drawablePadding="6dp"
android:text="@string/title_style_link_ffsend" android:text="@string/title_style_link_send"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvMetadataRemark" /> app:layout_constraintTop_toBottomOf="@id/tvMetadataRemark" />
@ -141,7 +141,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="6dp" android:layout_marginTop="6dp"
android:labelFor="@+id/sbDLimit" android:labelFor="@+id/sbDLimit"
android:text="@string/title_style_link_ffsend_dlimit" android:text="@string/title_style_link_send_dlimit"
android:textAppearance="@style/TextAppearance.AppCompat.Small" android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btnUpload" /> app:layout_constraintTop_toBottomOf="@id/btnUpload" />
@ -162,7 +162,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="6dp" android:layout_marginTop="6dp"
android:labelFor="@+id/sbTLimit" android:labelFor="@+id/sbTLimit"
android:text="@string/title_style_link_ffsend_tlimit" android:text="@string/title_style_link_send_tlimit"
android:textAppearance="@style/TextAppearance.AppCompat.Small" android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/sbDLimit" /> app:layout_constraintTop_toBottomOf="@id/sbDLimit" />

View File

@ -439,18 +439,18 @@
app:srcCompat="@drawable/twotone_info_24" /> app:srcCompat="@drawable/twotone_info_24" />
<androidx.appcompat.widget.SwitchCompat <androidx.appcompat.widget.SwitchCompat
android:id="@+id/swFFSend" android:id="@+id/swSend"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="12dp" android:layout_marginTop="12dp"
android:text="@string/title_advanced_ffsend" android:text="@string/title_advanced_send"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/ibVirusTotal" app:layout_constraintTop_toBottomOf="@id/ibVirusTotal"
app:switchPadding="12dp" /> app:switchPadding="12dp" />
<EditText <EditText
android:id="@+id/etFFSend" android:id="@+id/etSend"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="12dp" android:layout_marginTop="12dp"
@ -459,17 +459,17 @@
android:textAppearance="@style/TextAppearance.AppCompat.Small" android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swFFSend" /> app:layout_constraintTop_toBottomOf="@id/swSend" />
<ImageButton <ImageButton
android:id="@+id/ibFFSend" android:id="@+id/ibSend"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="12dp" android:layout_marginTop="12dp"
android:contentDescription="@string/title_info" android:contentDescription="@string/title_info"
android:tooltipText="@string/title_info" android:tooltipText="@string/title_info"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/etFFSend" app:layout_constraintTop_toBottomOf="@id/etSend"
app:srcCompat="@drawable/twotone_info_24" /> app:srcCompat="@drawable/twotone_info_24" />
<androidx.appcompat.widget.SwitchCompat <androidx.appcompat.widget.SwitchCompat
@ -481,7 +481,7 @@
android:text="@string/title_advanced_updates" android:text="@string/title_advanced_updates"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/ibFFSend" app:layout_constraintTop_toBottomOf="@id/ibSend"
app:switchPadding="12dp" /> app:switchPadding="12dp" />
<ImageButton <ImageButton
@ -634,10 +634,10 @@
app:constraint_referenced_ids="swVirusTotal,tvVirusTotalPrivacy,ibVirusTotal,etVirusTotal" /> app:constraint_referenced_ids="swVirusTotal,tvVirusTotalPrivacy,ibVirusTotal,etVirusTotal" />
<androidx.constraintlayout.widget.Group <androidx.constraintlayout.widget.Group
android:id="@+id/grpFFSend" android:id="@+id/grpSend"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
app:constraint_referenced_ids="swFFSend,etFFSend,ibFFSend" /> app:constraint_referenced_ids="swSend,etSend,ibSend" />
<androidx.constraintlayout.widget.Group <androidx.constraintlayout.widget.Group
android:id="@+id/grpUpdates" android:id="@+id/grpUpdates"

View File

@ -744,7 +744,7 @@
<string name="title_advanced_lt">LanguageTool integration</string> <string name="title_advanced_lt">LanguageTool integration</string>
<string name="title_advanced_deepl">DeepL integration</string> <string name="title_advanced_deepl">DeepL integration</string>
<string name="title_advanced_virus_total">VirusTotal integration</string> <string name="title_advanced_virus_total">VirusTotal integration</string>
<string name="title_advanced_ffsend" translatable="false">FFSend integration</string> <string name="title_advanced_send" translatable="false">Send integration</string>
<string name="title_advanced_sdcard">I want to use an sdcard</string> <string name="title_advanced_sdcard">I want to use an sdcard</string>
<string name="title_advanced_watchdog">Periodically check if FairEmail is still active</string> <string name="title_advanced_watchdog">Periodically check if FairEmail is still active</string>
<string name="title_advanced_updates">Check for GitHub updates</string> <string name="title_advanced_updates">Check for GitHub updates</string>
@ -1429,9 +1429,9 @@
<string name="title_style_link_title">Title</string> <string name="title_style_link_title">Title</string>
<string name="title_style_link_metadata">Fetch title</string> <string name="title_style_link_metadata">Fetch title</string>
<string name="title_style_link_metadata_remark">This will fetch the title at the entered address</string> <string name="title_style_link_metadata_remark">This will fetch the title at the entered address</string>
<string name="title_style_link_ffsend" translatable="false">FFSend</string> <string name="title_style_link_send" translatable="false">Send</string>
<string name="title_style_link_ffsend_dlimit" translatable="false">Download limit (%1$s)</string> <string name="title_style_link_send_dlimit" translatable="false">Download limit (%1$s)</string>
<string name="title_style_link_ffsend_tlimit" translatable="false">Time limit (%1$s)</string> <string name="title_style_link_send_tlimit" translatable="false">Time limit (%1$s)</string>
<string name="title_add_image">Add image</string> <string name="title_add_image">Add image</string>
<string name="title_add_image_inline">Insert</string> <string name="title_add_image_inline">Insert</string>