Context menu item to save an image as a sticker (Cheogram)
This commit is contained in:
parent
4325640fd5
commit
1993bce311
6 changed files with 100 additions and 0 deletions
|
@ -111,6 +111,7 @@ dependencies {
|
|||
implementation 'com.splitwise:tokenautocomplete:3.0.2'
|
||||
implementation 'com.github.singpolyma:android-identicons:master-SNAPSHOT'
|
||||
implementation 'com.github.woltapp:blurhash:master'
|
||||
implementation 'androidx.documentfile:documentfile:1.0.1'
|
||||
}
|
||||
|
||||
ext {
|
||||
|
|
|
@ -1394,6 +1394,13 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable
|
|||
return size == null ? 0 : size;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
Element file = getFileElement();
|
||||
if (file == null) return null;
|
||||
|
||||
return file.findChildContent("name", file.getNamespace());
|
||||
}
|
||||
|
||||
public Element toSims() {
|
||||
if (sims == null) sims = new Element("reference", "urn:xmpp:reference:0");
|
||||
sims.setAttribute("type", "data");
|
||||
|
|
|
@ -51,6 +51,7 @@ import androidx.annotation.RequiresApi;
|
|||
import androidx.annotation.StringRes;
|
||||
import androidx.core.content.FileProvider;
|
||||
import androidx.exifinterface.media.ExifInterface;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.io.ByteStreams;
|
||||
|
@ -668,6 +669,35 @@ public class FileBackend {
|
|||
return FileUtils.getPath(mXmppConnectionService, uri);
|
||||
}
|
||||
|
||||
|
||||
public void copyFileToDocumentFile(Context ctx, File file, DocumentFile df, String name) throws FileCopyException {
|
||||
Log.d(
|
||||
Config.LOGTAG,
|
||||
"copy file (" + file + ") to " + df + " / " + name);
|
||||
final DocumentFile dff = df.createFile(MimeUtils.guessMimeTypeFromUri(ctx, getUriForFile(ctx, file)), name);
|
||||
try (final InputStream is = new FileInputStream(file);
|
||||
final OutputStream os =
|
||||
mXmppConnectionService.getContentResolver().openOutputStream(dff.getUri())) {
|
||||
if (is == null) {
|
||||
throw new FileCopyException(R.string.error_file_not_found);
|
||||
}
|
||||
try {
|
||||
ByteStreams.copy(is, os);
|
||||
os.flush();
|
||||
} catch (IOException e) {
|
||||
throw new FileWriterException(file);
|
||||
}
|
||||
} catch (final FileNotFoundException e) {
|
||||
throw new FileCopyException(R.string.error_file_not_found);
|
||||
} catch (final FileWriterException e) {
|
||||
throw new FileCopyException(R.string.error_unable_to_create_temporary_file);
|
||||
} catch (final SecurityException | IllegalStateException e) {
|
||||
throw new FileCopyException(R.string.error_security_exception);
|
||||
} catch (final IOException e) {
|
||||
throw new FileCopyException(R.string.error_io_exception);
|
||||
}
|
||||
}
|
||||
|
||||
private void copyFileToPrivateStorage(File file, Uri uri) throws FileCopyException {
|
||||
Log.d(Config.LOGTAG, "copy file (" + uri.toString() + ") to private storage " + file.getAbsolutePath());
|
||||
file.getParentFile().mkdirs();
|
||||
|
|
|
@ -74,6 +74,9 @@ import android.widget.Toast;
|
|||
import eu.siacs.conversations.utils.Emoticons;
|
||||
import de.monocles.chat.BobTransfer;
|
||||
import java.net.URISyntaxException;
|
||||
import android.os.Environment;
|
||||
import android.os.storage.StorageManager;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
import androidx.activity.OnBackPressedCallback;
|
||||
import androidx.annotation.IdRes;
|
||||
|
@ -96,6 +99,7 @@ import com.google.common.base.Optional;
|
|||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.w3c.dom.Node;
|
||||
import java.io.File;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
|
@ -198,6 +202,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
|
|||
public static final int ATTACHMENT_CHOICE = 0x0300;
|
||||
public static final int REQUEST_START_AUDIO_CALL = 0x213;
|
||||
public static final int REQUEST_START_VIDEO_CALL = 0x214;
|
||||
public static final int REQUEST_SAVE_STICKER = 0x215;
|
||||
public static final int ATTACHMENT_CHOICE_CHOOSE_IMAGE = 0x0301;
|
||||
public static final int ATTACHMENT_CHOICE_TAKE_PHOTO = 0x0302;
|
||||
public static final int ATTACHMENT_CHOICE_CHOOSE_FILE = 0x0303;
|
||||
|
@ -245,6 +250,8 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
|
|||
|
||||
private boolean reInitRequiredOnStart = true;
|
||||
private int identiconWidth = -1;
|
||||
private File savingAsSticker = null;
|
||||
private String savingAsStickerName = null;
|
||||
private MediaPreviewAdapter mediaPreviewAdapter;
|
||||
private final OnClickListener clickToMuc = new OnClickListener() {
|
||||
|
||||
|
@ -1126,6 +1133,24 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
|
|||
|
||||
private void handlePositiveActivityResult(int requestCode, final Intent data) {
|
||||
switch (requestCode) {
|
||||
case REQUEST_SAVE_STICKER:
|
||||
final DocumentFile df = DocumentFile.fromTreeUri(activity, data.getData());
|
||||
final File f = savingAsSticker;
|
||||
final String existingName = savingAsStickerName;
|
||||
savingAsSticker = null;
|
||||
savingAsStickerName = null;
|
||||
activity.quickEdit(existingName, R.string.sticker_name, (name) -> {
|
||||
try {
|
||||
activity.xmppConnectionService.getFileBackend().copyFileToDocumentFile(activity, f, df, name);
|
||||
} catch (final FileBackend.FileCopyException e) {
|
||||
Toast.makeText(activity, e.getResId(), Toast.LENGTH_SHORT).show();
|
||||
return null;
|
||||
}
|
||||
|
||||
Toast.makeText(activity, "Sticker saved", Toast.LENGTH_SHORT).show();
|
||||
return null;
|
||||
});
|
||||
break;
|
||||
case REQUEST_TRUST_KEYS_TEXT:
|
||||
sendMessage();
|
||||
break;
|
||||
|
@ -1610,6 +1635,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
|
|||
MenuItem shareWith = menu.findItem(R.id.share_with);
|
||||
MenuItem sendAgain = menu.findItem(R.id.send_again);
|
||||
MenuItem copyUrl = menu.findItem(R.id.copy_url);
|
||||
MenuItem saveAsSticker = menu.findItem(R.id.save_as_sticker);
|
||||
MenuItem cancelTransmission = menu.findItem(R.id.cancel_transmission);
|
||||
MenuItem downloadFile = menu.findItem(R.id.download_file);
|
||||
MenuItem deleteFile = menu.findItem(R.id.delete_file);
|
||||
|
@ -1677,6 +1703,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
|
|||
final String path = m.getRelativeFilePath();
|
||||
Log.d(Config.LOGTAG, "Path = " + path);
|
||||
if (path == null || !path.startsWith("/") || path.contains(getConversationsDirectory(this.activity, "null").getAbsolutePath())) {
|
||||
saveAsSticker.setVisible(true);
|
||||
deleteFile.setVisible(true);
|
||||
deleteFile.setTitle(activity.getString(R.string.delete_x_file, UIHelper.getFileDescriptionString(activity, m)));
|
||||
}
|
||||
|
@ -1760,6 +1787,9 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
|
|||
case R.id.copy_url:
|
||||
ShareUtil.copyUrlToClipboard(activity, selectedMessage);
|
||||
return true;
|
||||
case R.id.save_as_sticker:
|
||||
saveAsSticker(selectedMessage);
|
||||
return true;
|
||||
case R.id.download_file:
|
||||
startDownloadable(selectedMessage);
|
||||
return true;
|
||||
|
@ -2707,6 +2737,32 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
|
|||
builder.create().show();
|
||||
}
|
||||
|
||||
private void saveAsSticker(final Message m) {
|
||||
String existingName = m.getFileParams() != null && m.getFileParams().getName() != null ? m.getFileParams().getName() : "";
|
||||
existingName = existingName.lastIndexOf(".") == -1 ? existingName : existingName.substring(0, existingName.lastIndexOf("."));
|
||||
saveAsSticker(activity.xmppConnectionService.getFileBackend().getFile(m), existingName);
|
||||
}
|
||||
|
||||
private void saveAsSticker(final File file, final String name) {
|
||||
savingAsSticker = file;
|
||||
savingAsStickerName = name;
|
||||
|
||||
Intent intent = ((StorageManager) activity.getSystemService(Context.STORAGE_SERVICE)).getPrimaryStorageVolume().createOpenDocumentTreeIntent();
|
||||
|
||||
SharedPreferences p = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||
final String dir = p.getString("sticker_directory", "Stickers");
|
||||
if (dir.startsWith("content://")) {
|
||||
intent.putExtra("android.provider.extra.INITIAL_URI", Uri.parse(dir));
|
||||
} else {
|
||||
new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/" + dir + "/User Pack").mkdirs();
|
||||
Uri uri = intent.getParcelableExtra("android.provider.extra.INITIAL_URI");
|
||||
intent.putExtra("android.provider.extra.INITIAL_URI", Uri.parse(uri.toString().replace("/root/", "/document/") + "%3APictures%2F" + dir));
|
||||
}
|
||||
|
||||
Toast.makeText(activity, "Choose a sticker pack to add this sticker to", Toast.LENGTH_SHORT).show();
|
||||
startActivityForResult(Intent.createChooser(intent, "Choose sticker pack"), REQUEST_SAVE_STICKER);
|
||||
}
|
||||
|
||||
private void deleteFile(final Message message) {
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity());
|
||||
builder.setNegativeButton(R.string.cancel, null);
|
||||
|
|
|
@ -47,6 +47,10 @@
|
|||
android:id="@+id/copy_url"
|
||||
android:title="@string/copy_original_url"
|
||||
android:visible="false" />
|
||||
<item
|
||||
android:id="@+id/save_as_sticker"
|
||||
android:title="@string/save_as_sticker"
|
||||
android:visible="false" />
|
||||
<item
|
||||
android:id="@+id/show_error_message"
|
||||
android:title="@string/show_error_message"
|
||||
|
|
|
@ -1276,4 +1276,6 @@
|
|||
<string name="thread_marker">Thread Marker</string>
|
||||
<string name="thread_locked">Thread locked</string>
|
||||
<string name="tags">Tags</string>
|
||||
<string name="save_as_sticker">Save as Sticker</string>
|
||||
<string name="sticker_name">Sticker Name</string>
|
||||
</resources>
|
||||
|
|
Loading…
Add table
Reference in a new issue