aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java24
-rw-r--r--src/main/java/de/pixart/messenger/persistance/FileBackend.java77
-rw-r--r--src/main/java/de/pixart/messenger/services/ExportLogsService.java4
-rw-r--r--src/main/java/de/pixart/messenger/services/XmppConnectionService.java9
-rw-r--r--src/main/java/de/pixart/messenger/ui/ConferenceDetailsActivity.java22
-rw-r--r--src/main/java/de/pixart/messenger/ui/ContactDetailsActivity.java23
-rw-r--r--src/main/java/de/pixart/messenger/ui/ConversationFragment.java2
-rw-r--r--src/main/java/de/pixart/messenger/ui/RecordingActivity.java2
-rw-r--r--src/main/java/de/pixart/messenger/ui/UpdaterActivity.java4
-rw-r--r--src/main/java/de/pixart/messenger/ui/WelcomeActivity.java14
-rw-r--r--src/main/java/de/pixart/messenger/ui/adapter/MediaAdapter.java226
-rw-r--r--src/main/java/de/pixart/messenger/ui/adapter/MediaPreviewAdapter.java50
-rw-r--r--src/main/java/de/pixart/messenger/ui/adapter/MessageAdapter.java26
-rw-r--r--src/main/java/de/pixart/messenger/ui/interfaces/OnMediaLoaded.java10
-rw-r--r--src/main/java/de/pixart/messenger/ui/util/Attachment.java14
-rw-r--r--src/main/java/de/pixart/messenger/ui/util/GridManager.java71
-rw-r--r--src/main/java/de/pixart/messenger/ui/util/ViewUtil.java50
-rw-r--r--src/main/java/de/pixart/messenger/ui/widget/SquareFrameLayout.java25
-rw-r--r--src/main/res/layout/activity_contact_details.xml54
-rw-r--r--src/main/res/layout/activity_muc_details.xml46
-rw-r--r--src/main/res/layout/media.xml16
-rw-r--r--src/main/res/values/dimens.xml3
-rw-r--r--src/main/res/values/strings.xml1
23 files changed, 651 insertions, 122 deletions
diff --git a/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java b/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java
index 94710b86e..54d99ec43 100644
--- a/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java
+++ b/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java
@@ -35,6 +35,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;
import de.pixart.messenger.Config;
@@ -787,6 +788,29 @@ public class DatabaseBackend extends SQLiteOpenHelper {
};
}
+ public List<FilePath> getRelativeFilePaths(Account account, Jid jid, int limit) {
+ SQLiteDatabase db = this.getReadableDatabase();
+ final String SQL = "select uuid,relativeFilePath from messages where type in (1,2) and conversationUuid=(select uuid from conversations where accountUuid=? and (contactJid=? or contactJid like ?)) order by timeSent desc";
+ final String[] args = {account.getUuid(), jid.asBareJid().toEscapedString(), jid.asBareJid().toEscapedString() + "/%"};
+ Cursor cursor = db.rawQuery(SQL + (limit > 0 ? " limit " + String.valueOf(limit) : ""), args);
+ List<FilePath> filesPaths = new ArrayList<>();
+ while (cursor.moveToNext()) {
+ filesPaths.add(new FilePath(cursor.getString(0), cursor.getString(1)));
+ }
+ cursor.close();
+ return filesPaths;
+ }
+
+ public static class FilePath {
+ public final UUID uuid;
+ public final String path;
+
+ private FilePath(String uuid, String path) {
+ this.uuid = UUID.fromString(uuid);
+ this.path = path;
+ }
+ }
+
public Conversation findConversation(final Account account, final Jid contactJid) {
SQLiteDatabase db = this.getReadableDatabase();
String[] selectionArgs = {account.getUuid(),
diff --git a/src/main/java/de/pixart/messenger/persistance/FileBackend.java b/src/main/java/de/pixart/messenger/persistance/FileBackend.java
index 35967e624..92bb84e33 100644
--- a/src/main/java/de/pixart/messenger/persistance/FileBackend.java
+++ b/src/main/java/de/pixart/messenger/persistance/FileBackend.java
@@ -46,6 +46,7 @@ import java.security.DigestOutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
@@ -81,8 +82,8 @@ public class FileBackend {
}
private void createNoMedia() {
- final File nomedia_files = new File(getConversationsDirectory("Files", true) + ".nomedia");
- final File nomedia_audios = new File(getConversationsDirectory("Audios", true) + ".nomedia");
+ final File nomedia_files = new File(getConversationsDirectory("Files") + ".nomedia");
+ final File nomedia_audios = new File(getConversationsDirectory("Audios") + ".nomedia");
if (!nomedia_files.exists()) {
try {
nomedia_files.createNewFile();
@@ -100,8 +101,8 @@ public class FileBackend {
}
public void updateMediaScanner(File file) {
- if (file.getAbsolutePath().startsWith(getConversationsDirectory("Images", true))
- || file.getAbsolutePath().startsWith(getConversationsDirectory("Videos", true))) {
+ if (file.getAbsolutePath().startsWith(getConversationsDirectory("Images"))
+ || file.getAbsolutePath().startsWith(getConversationsDirectory("Videos"))) {
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
intent.setData(Uri.fromFile(file));
mXmppConnectionService.sendBroadcast(intent);
@@ -130,13 +131,13 @@ public class FileBackend {
file = new DownloadableFile(path);
} else {
if (mime != null && mime.startsWith("image")) {
- file = new DownloadableFile(getConversationsDirectory("Images", true) + path);
+ file = new DownloadableFile(getConversationsDirectory("Images") + path);
} else if (mime != null && mime.startsWith("video")) {
- file = new DownloadableFile(getConversationsDirectory("Videos", true) + path);
+ file = new DownloadableFile(getConversationsDirectory("Videos") + path);
} else if (mime != null && mime.startsWith("audio")) {
- file = new DownloadableFile(getConversationsDirectory("Audios", true) + path);
+ file = new DownloadableFile(getConversationsDirectory("Audios") + path);
} else {
- file = new DownloadableFile(getConversationsDirectory("Files", true) + path);
+ file = new DownloadableFile(getConversationsDirectory("Files") + path);
}
}
return file;
@@ -152,7 +153,7 @@ public class FileBackend {
}
final DownloadableFile file = getFileForPath(path, message.getMimeType());
if (encrypted) {
- return new DownloadableFile(getConversationsDirectory("Files", true) + file.getName() + ".pgp");
+ return new DownloadableFile(getConversationsDirectory("Files") + file.getName() + ".pgp");
} else {
return file;
}
@@ -202,31 +203,43 @@ public class FileBackend {
return true;
}
- public static String getDirectoryName(final String type, final boolean isMedia) {
- String media = "";
- if (isMedia) {
- media = "Media/Pix-Art Messenger ";
+ public List<Attachment> convertToAttachments(List<DatabaseBackend.FilePath> relativeFilePaths) {
+ List<Attachment> attachments = new ArrayList<>();
+ for (DatabaseBackend.FilePath relativeFilePath : relativeFilePaths) {
+ final String mime = MimeUtils.guessMimeTypeFromExtension(MimeUtils.extractRelevantExtension(relativeFilePath.path));
+ Log.d(Config.LOGTAG, "mime=" + mime);
+ File file = getFileForPath(relativeFilePath.path, mime);
+ if (file.exists()) {
+ attachments.add(Attachment.of(relativeFilePath.uuid, file, mime));
+ } else {
+ Log.d(Config.LOGTAG, "file " + file.getAbsolutePath() + " doesn't exist");
+ }
}
- if (type == "null" || type == null) {
- return "/Pix-Art Messenger/";
+ return attachments;
+ }
+
+ public static String getConversationsDirectory(final String type) {
+ if (type.equalsIgnoreCase("null") || type == null) {
+ return getAppMediaDirectory() + "Pix-Art Messenger" + "/";
} else {
- return "/Pix-Art Messenger" + "/" + media + type + "/";
+ return getAppMediaDirectory() + "Pix-Art Messenger" + " " + type + "/";
}
}
- public static String getConversationsDirectory(final String type, final boolean isMedia) {
- String DirName = null;
- if (type != "null" || type != null) {
- DirName = type;
- }
- String path = Environment.getExternalStorageDirectory().getAbsolutePath() + getDirectoryName(DirName, isMedia);
- File createFolders = new File(path);
- if (!createFolders.exists()) {
- Log.d(Config.LOGTAG, "creating directory " + createFolders);
- createFolders.mkdirs();
- }
- return path;
+ public static String getAppMediaDirectory() {
+ return Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + "Pix-Art Messenger" + "/Media/";
+ }
+
+ public static String getBackupDirectory() {
+ return Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + "Pix-Art Messenger" + "/Database/";
+ }
+
+ public static String getAppLogsDirectory() {
+ return Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + "Pix-Art Messenger" + "/Chats/";
+ }
+ public static String getAppUpdateDirectory() {
+ return Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + "Pix-Art Messenger" + "/Update/";
}
private Bitmap resize(final Bitmap originalBitmap, int size) throws IOException {
@@ -298,7 +311,7 @@ public class FileBackend {
Log.d(Config.LOGTAG, "File path = null");
return false;
}
- if (path.contains(getDirectoryName("null", true))) {
+ if (path.contains(getConversationsDirectory("null"))) {
Log.d(Config.LOGTAG, "File " + path + " is in our directory");
return true;
}
@@ -1061,12 +1074,12 @@ public class FileBackend {
}
public Bitmap getPreviewForUri(Attachment attachment, int size, boolean cacheOnly) {
+ final String key = "attachment_" + attachment.getUuid().toString() + "_" + String.valueOf(size);
final LruCache<String, Bitmap> cache = mXmppConnectionService.getBitmapCache();
- Bitmap bitmap = cache.get(attachment.getUuid().toString());
+ Bitmap bitmap = cache.get(key);
if (bitmap != null || cacheOnly) {
return bitmap;
}
- Log.d(Config.LOGTAG, "attachment mime=" + attachment.getMime());
if (attachment.getMime() != null && attachment.getMime().startsWith("video/")) {
bitmap = cropCenterSquareVideo(attachment.getUri(), size);
drawOverlay(bitmap, R.drawable.play_video, 0.75f);
@@ -1079,7 +1092,7 @@ public class FileBackend {
bitmap = withGifOverlay;
}
}
- cache.put(attachment.getUuid().toString(), bitmap);
+ cache.put(key, bitmap);
return bitmap;
}
diff --git a/src/main/java/de/pixart/messenger/services/ExportLogsService.java b/src/main/java/de/pixart/messenger/services/ExportLogsService.java
index b0da108ba..e66873acc 100644
--- a/src/main/java/de/pixart/messenger/services/ExportLogsService.java
+++ b/src/main/java/de/pixart/messenger/services/ExportLogsService.java
@@ -41,7 +41,7 @@ import static de.pixart.messenger.ui.SettingsActivity.USE_MULTI_ACCOUNTS;
public class ExportLogsService extends XmppConnectionService {
private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
- private static final String DIRECTORY_STRING_FORMAT = FileBackend.getConversationsDirectory("Chats", false) + "%s";
+ private static final String DIRECTORY_STRING_FORMAT = FileBackend.getAppLogsDirectory() + "%s";
private static final String MESSAGE_STRING_FORMAT = "(%s) %s: %s\n";
private static AtomicBoolean running = new AtomicBoolean(false);
boolean ReadableLogsEnabled = false;
@@ -171,7 +171,7 @@ public class ExportLogsService extends XmppConnectionService {
// Get hold of the db:
FileInputStream InputFile = new FileInputStream(this.getDatabasePath(DatabaseBackend.DATABASE_NAME));
// Set the output folder on the SDcard
- File directory = new File(FileBackend.getConversationsDirectory("Database", false));
+ File directory = new File(FileBackend.getBackupDirectory());
// Create the folder if it doesn't exist:
if (!directory.exists()) {
boolean directory_created = directory.mkdirs();
diff --git a/src/main/java/de/pixart/messenger/services/XmppConnectionService.java b/src/main/java/de/pixart/messenger/services/XmppConnectionService.java
index 25d4fb2b8..cd35198dc 100644
--- a/src/main/java/de/pixart/messenger/services/XmppConnectionService.java
+++ b/src/main/java/de/pixart/messenger/services/XmppConnectionService.java
@@ -116,6 +116,7 @@ import de.pixart.messenger.persistance.FileBackend;
import de.pixart.messenger.ui.SettingsActivity;
import de.pixart.messenger.ui.UiCallback;
import de.pixart.messenger.ui.interfaces.OnAvatarPublication;
+import de.pixart.messenger.ui.interfaces.OnMediaLoaded;
import de.pixart.messenger.ui.interfaces.OnSearchResultsAvailable;
import de.pixart.messenger.utils.Compatibility;
import de.pixart.messenger.utils.ConversationsFileObserver;
@@ -2681,6 +2682,14 @@ public class XmppConnectionService extends Service {
return false;
}
+ public void getAttachments(final Conversation conversation, int limit, final OnMediaLoaded onMediaLoaded) {
+ getAttachments(conversation.getAccount(), conversation.getJid().asBareJid(), limit, onMediaLoaded);
+ }
+
+ public void getAttachments(final Account account, final Jid jid, final int limit, final OnMediaLoaded onMediaLoaded) {
+ new Thread(() -> onMediaLoaded.onMediaLoaded(fileBackend.convertToAttachments(databaseBackend.getRelativeFilePaths(account, jid, limit)))).start();
+ }
+
public void persistSelfNick(MucOptions.User self) {
final Conversation conversation = self.getConversation();
Jid full = self.getFullJid();
diff --git a/src/main/java/de/pixart/messenger/ui/ConferenceDetailsActivity.java b/src/main/java/de/pixart/messenger/ui/ConferenceDetailsActivity.java
index 38479b459..fd7c66c18 100644
--- a/src/main/java/de/pixart/messenger/ui/ConferenceDetailsActivity.java
+++ b/src/main/java/de/pixart/messenger/ui/ConferenceDetailsActivity.java
@@ -32,6 +32,7 @@ import org.openintents.openpgp.util.OpenPgpUtils;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.List;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicInteger;
@@ -49,6 +50,10 @@ import de.pixart.messenger.entities.MucOptions.User;
import de.pixart.messenger.services.XmppConnectionService;
import de.pixart.messenger.services.XmppConnectionService.OnConversationUpdate;
import de.pixart.messenger.services.XmppConnectionService.OnMucRosterUpdate;
+import de.pixart.messenger.ui.adapter.MediaAdapter;
+import de.pixart.messenger.ui.interfaces.OnMediaLoaded;
+import de.pixart.messenger.ui.util.Attachment;
+import de.pixart.messenger.ui.util.GridManager;
import de.pixart.messenger.ui.util.MucDetailsContextMenuHelper;
import de.pixart.messenger.ui.util.MyLinkify;
import de.pixart.messenger.ui.util.SoftKeyboardUtils;
@@ -64,7 +69,7 @@ import rocks.xmpp.addr.Jid;
import static de.pixart.messenger.entities.Bookmark.printableValue;
import static de.pixart.messenger.utils.StringUtils.changed;
-public class ConferenceDetailsActivity extends XmppActivity implements OnConversationUpdate, OnMucRosterUpdate, XmppConnectionService.OnAffiliationChanged, XmppConnectionService.OnRoleChanged, XmppConnectionService.OnConfigurationPushed, TextWatcher {
+public class ConferenceDetailsActivity extends XmppActivity implements OnConversationUpdate, OnMucRosterUpdate, XmppConnectionService.OnAffiliationChanged, XmppConnectionService.OnRoleChanged, XmppConnectionService.OnConfigurationPushed, TextWatcher, OnMediaLoaded {
public static final String ACTION_VIEW_MUC = "view_muc";
private static final float INACTIVE_ALPHA = 0.4684f; //compromise between dark and light theme
private Conversation mConversation;
@@ -96,6 +101,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
}
};
private ActivityMucDetailsBinding binding;
+ private MediaAdapter mMediaAdapter;
private String uuid = null;
private User mSelectedUser = null;
@@ -319,6 +325,9 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
this.binding.mucEditTitle.addTextChangedListener(this);
this.binding.mucEditSubject.addTextChangedListener(this);
this.binding.mucEditSubject.addTextChangedListener(new StylingHelper.MessageEditorStyler(this.binding.mucEditSubject));
+ mMediaAdapter = new MediaAdapter(this, R.dimen.media_size);
+ this.binding.media.setAdapter(mMediaAdapter);
+ GridManager.setupLayoutManager(this, this.binding.media, R.dimen.media_size);
}
@Override
@@ -475,6 +484,15 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
return true;
}
+ @Override
+ public void onMediaLoaded(List<Attachment> attachments) {
+ runOnUiThread(() -> {
+ int limit = GridManager.getCurrentColumnCount(binding.media);
+ mMediaAdapter.setAttachments(attachments.subList(0, Math.min(limit, attachments.size())));
+ binding.mediaWrapper.setVisibility(attachments.size() > 0 ? View.VISIBLE : View.GONE);
+ });
+ }
+
protected void saveAsBookmark() {
xmppConnectionService.saveConversationAsBookmark(mConversation, mConversation.getMucOptions().getName());
updateView();
@@ -503,6 +521,8 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
if (uuid != null) {
this.mConversation = xmppConnectionService.findConversationByUuid(uuid);
if (this.mConversation != null) {
+ final int limit = GridManager.getCurrentColumnCount(this.binding.media);
+ xmppConnectionService.getAttachments(this.mConversation, limit, this);
updateView();
}
}
diff --git a/src/main/java/de/pixart/messenger/ui/ContactDetailsActivity.java b/src/main/java/de/pixart/messenger/ui/ContactDetailsActivity.java
index 5dce3fca2..d488419d2 100644
--- a/src/main/java/de/pixart/messenger/ui/ContactDetailsActivity.java
+++ b/src/main/java/de/pixart/messenger/ui/ContactDetailsActivity.java
@@ -30,6 +30,7 @@ import android.widget.Toast;
import org.openintents.openpgp.util.OpenPgpUtils;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@@ -45,6 +46,10 @@ import de.pixart.messenger.entities.Conversation;
import de.pixart.messenger.entities.ListItem;
import de.pixart.messenger.services.XmppConnectionService.OnAccountUpdate;
import de.pixart.messenger.services.XmppConnectionService.OnRosterUpdate;
+import de.pixart.messenger.ui.adapter.MediaAdapter;
+import de.pixart.messenger.ui.interfaces.OnMediaLoaded;
+import de.pixart.messenger.ui.util.Attachment;
+import de.pixart.messenger.ui.util.GridManager;
import de.pixart.messenger.utils.CryptoHelper;
import de.pixart.messenger.utils.IrregularUnicodeDetector;
import de.pixart.messenger.utils.MenuDoubleTabUtil;
@@ -57,12 +62,13 @@ import de.pixart.messenger.xmpp.OnUpdateBlocklist;
import de.pixart.messenger.xmpp.XmppConnection;
import rocks.xmpp.addr.Jid;
-public class ContactDetailsActivity extends OmemoActivity implements OnAccountUpdate, OnRosterUpdate, OnUpdateBlocklist, OnKeyStatusUpdated {
+public class ContactDetailsActivity extends OmemoActivity implements OnAccountUpdate, OnRosterUpdate, OnUpdateBlocklist, OnKeyStatusUpdated, OnMediaLoaded {
public static final String ACTION_VIEW_CONTACT = "view_contact";
private Contact contact;
private Conversation mConversation;
ActivityContactDetailsBinding binding;
+ private MediaAdapter mMediaAdapter;
private DialogInterface.OnClickListener removeFromRoster = new DialogInterface.OnClickListener() {
@Override
@@ -260,6 +266,9 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
this.mNotifyStatusButton = findViewById(R.id.notification_status_button);
this.mNotifyStatusButton.setOnClickListener(this.mNotifyStatusClickListener);
this.mNotifyStatusText = findViewById(R.id.notification_status_text);
+ mMediaAdapter = new MediaAdapter(this, R.dimen.media_size);
+ this.binding.media.setAdapter(mMediaAdapter);
+ GridManager.setupLayoutManager(this, this.binding.media, R.dimen.media_size);
}
@Override
@@ -279,6 +288,7 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
this.showDynamicTags = preferences.getBoolean(SettingsActivity.SHOW_DYNAMIC_TAGS, false);
this.showLastSeen = preferences.getBoolean("last_activity", false);
}
+ mMediaAdapter.setAttachments(Collections.emptyList());
}
@Override
@@ -657,6 +667,8 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
processFingerprintVerification(mPendingFingerprintVerificationUri);
mPendingFingerprintVerificationUri = null;
}
+ final int limit = GridManager.getCurrentColumnCount(this.binding.media);
+ xmppConnectionService.getAttachments(account, contact.getJid().asBareJid(), limit, this);
populateView();
}
}
@@ -676,4 +688,13 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
Toast.makeText(this, R.string.invalid_barcode, Toast.LENGTH_SHORT).show();
}
}
+
+ @Override
+ public void onMediaLoaded(List<Attachment> attachments) {
+ runOnUiThread(() -> {
+ int limit = GridManager.getCurrentColumnCount(binding.media);
+ mMediaAdapter.setAttachments(attachments.subList(0, Math.min(limit, attachments.size())));
+ binding.mediaWrapper.setVisibility(attachments.size() > 0 ? View.VISIBLE : View.GONE);
+ });
+ }
}
diff --git a/src/main/java/de/pixart/messenger/ui/ConversationFragment.java b/src/main/java/de/pixart/messenger/ui/ConversationFragment.java
index 9961e014b..c2e2902ac 100644
--- a/src/main/java/de/pixart/messenger/ui/ConversationFragment.java
+++ b/src/main/java/de/pixart/messenger/ui/ConversationFragment.java
@@ -1375,7 +1375,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
if (m.isFileOrImage() && !deleted) {
String path = m.getRelativeFilePath();
Log.d(Config.LOGTAG, "Path = " + path);
- if (path == null || !path.startsWith("/") || path.contains(FileBackend.getConversationsDirectory("null", false))) {
+ if (path == null || !path.startsWith("/") || path.contains(FileBackend.getConversationsDirectory("null"))) {
deleteFile.setVisible(true);
deleteFile.setTitle(activity.getString(R.string.delete_x_file, UIHelper.getFileDescriptionString(activity, m)));
}
diff --git a/src/main/java/de/pixart/messenger/ui/RecordingActivity.java b/src/main/java/de/pixart/messenger/ui/RecordingActivity.java
index 455bbf3c3..31dc1681a 100644
--- a/src/main/java/de/pixart/messenger/ui/RecordingActivity.java
+++ b/src/main/java/de/pixart/messenger/ui/RecordingActivity.java
@@ -127,7 +127,7 @@ public class RecordingActivity extends Activity implements View.OnClickListener
private static File generateOutputFilename(Context context) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmssSSS", Locale.US);
- return new File(FileBackend.getConversationsDirectory("Audios", true) + "/"
+ return new File(FileBackend.getConversationsDirectory("Audios")
+ dateFormat.format(new Date())
+ ".m4a");
}
diff --git a/src/main/java/de/pixart/messenger/ui/UpdaterActivity.java b/src/main/java/de/pixart/messenger/ui/UpdaterActivity.java
index 959060101..9e35d7ebf 100644
--- a/src/main/java/de/pixart/messenger/ui/UpdaterActivity.java
+++ b/src/main/java/de/pixart/messenger/ui/UpdaterActivity.java
@@ -114,7 +114,7 @@ public class UpdaterActivity extends XmppActivity {
store = null;
}
//delete old downloaded localVersion files
- File dir = new File(FileBackend.getConversationsDirectory("Update", false));
+ File dir = new File(FileBackend.getAppUpdateDirectory());
if (dir.isDirectory()) {
String[] children = dir.list();
for (String aChildren : children) {
@@ -291,7 +291,7 @@ public class UpdaterActivity extends XmppActivity {
private class DownloadTask extends AsyncTask<String, Integer, String> {
- File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + FileBackend.getDirectoryName("Update", false));
+ File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + FileBackend.getAppUpdateDirectory());
File file = new File(dir, FileName);
private Context context;
private PowerManager.WakeLock mWakeLock;
diff --git a/src/main/java/de/pixart/messenger/ui/WelcomeActivity.java b/src/main/java/de/pixart/messenger/ui/WelcomeActivity.java
index 9d5b76c1c..e2bf9d8e9 100644
--- a/src/main/java/de/pixart/messenger/ui/WelcomeActivity.java
+++ b/src/main/java/de/pixart/messenger/ui/WelcomeActivity.java
@@ -193,7 +193,7 @@ public class WelcomeActivity extends XmppActivity {
private boolean BackupAvailable() {
// Set the folder on the SDcard
- File filePath = new File(FileBackend.getConversationsDirectory("Database", false) + "database.db.crypt");
+ File filePath = new File(FileBackend.getBackupDirectory() + "database.db.crypt");
Log.d(Config.LOGTAG, "DB Path: " + filePath.toString());
if (filePath.exists()) {
Log.d(Config.LOGTAG, "DB Path existing");
@@ -206,11 +206,11 @@ public class WelcomeActivity extends XmppActivity {
private void checkDatabase(String DecryptionKey) throws IOException {
// Set the folder on the SDcard
- File directory = new File(FileBackend.getConversationsDirectory("Database", false));
+ File directory = new File(FileBackend.getBackupDirectory());
// Set the input file stream up:
- FileInputStream InputFile = new FileInputStream(directory.getPath() + "/database.db.crypt");
+ FileInputStream InputFile = new FileInputStream(directory.getPath() + "database.db.crypt");
// Temp output for DB checks
- File TempFile = new File(directory.getPath() + "/database.bak");
+ File TempFile = new File(directory.getPath() + "database.bak");
FileOutputStream OutputTemp = new FileOutputStream(TempFile);
try {
@@ -286,11 +286,11 @@ public class WelcomeActivity extends XmppActivity {
// Set location for the db:
final OutputStream OutputFile = new FileOutputStream(this.getDatabasePath(DatabaseBackend.DATABASE_NAME));
// Set the folder on the SDcard
- File directory = new File(FileBackend.getConversationsDirectory("Database", false));
+ File directory = new File(FileBackend.getBackupDirectory());
// Set the input file stream up:
- final InputStream InputFile = new FileInputStream(directory.getPath() + "/database.bak");
+ final InputStream InputFile = new FileInputStream(directory.getPath() + "database.bak");
//set temp file
- File TempFile = new File(directory.getPath() + "/database.bak");
+ File TempFile = new File(directory.getPath() + "database.bak");
// Transfer bytes from the input file to the output file
byte[] buffer = new byte[1024];
diff --git a/src/main/java/de/pixart/messenger/ui/adapter/MediaAdapter.java b/src/main/java/de/pixart/messenger/ui/adapter/MediaAdapter.java
new file mode 100644
index 000000000..0472c6d11
--- /dev/null
+++ b/src/main/java/de/pixart/messenger/ui/adapter/MediaAdapter.java
@@ -0,0 +1,226 @@
+package de.pixart.messenger.ui.adapter;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.databinding.DataBindingUtil;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.AsyncTask;
+import android.support.annotation.AttrRes;
+import android.support.annotation.DimenRes;
+import android.support.annotation.NonNull;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.RejectedExecutionException;
+
+import de.pixart.messenger.R;
+import de.pixart.messenger.databinding.MediaBinding;
+import de.pixart.messenger.ui.XmppActivity;
+import de.pixart.messenger.ui.util.Attachment;
+import de.pixart.messenger.ui.util.StyledAttributes;
+import de.pixart.messenger.ui.util.ViewUtil;
+
+public class MediaAdapter extends RecyclerView.Adapter<MediaAdapter.MediaViewHolder> {
+
+ private static final List<String> DOCUMENT_MIMES = Arrays.asList(
+ "application/pdf",
+ "application/vnd.oasis.opendocument.text",
+ "application/msword",
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+ "text/x-tex",
+ "text/plain"
+ );
+
+ private final ArrayList<Attachment> attachments = new ArrayList<>();
+
+ private final XmppActivity activity;
+
+ private int mediaSize = 0;
+
+ public MediaAdapter(XmppActivity activity, @DimenRes int mediaSize) {
+ this.activity = activity;
+ this.mediaSize = Math.round(activity.getResources().getDimension(mediaSize));
+ }
+
+ public static void setMediaSize(RecyclerView recyclerView, int mediaSize) {
+ RecyclerView.Adapter adapter = recyclerView.getAdapter();
+ if (adapter instanceof MediaAdapter) {
+ ((MediaAdapter) adapter).setMediaSize(mediaSize);
+ }
+ }
+
+ private static @AttrRes
+ int getImageAttr(Attachment attachment) {
+ final @AttrRes int attr;
+ if (attachment.getType() == Attachment.Type.LOCATION) {
+ attr = R.attr.media_preview_location;
+ } else if (attachment.getType() == Attachment.Type.RECORDING) {
+ attr = R.attr.media_preview_recording;
+ } else {
+ final String mime = attachment.getMime();
+ if (mime == null) {
+ attr = R.attr.media_preview_unknown;
+ } else if (mime.startsWith("audio/")) {
+ attr = R.attr.media_preview_audio;
+ } else if (mime.equals("text/calendar") || (mime.equals("text/x-vcalendar"))) {
+ attr = R.attr.media_preview_calendar;
+ } else if (mime.equals("text/x-vcard")) {
+ attr = R.attr.media_preview_contact;
+ } else if (mime.equals("application/vnd.android.package-archive")) {
+ attr = R.attr.media_preview_app;
+ } else if (mime.equals("application/zip") || mime.equals("application/rar")) {
+ attr = R.attr.media_preview_archive;
+ } else if (DOCUMENT_MIMES.contains(mime)) {
+ attr = R.attr.media_preview_document;
+ } else {
+ attr = R.attr.media_preview_unknown;
+ }
+ }
+ return attr;
+ }
+
+ public static void renderPreview(Context context, Attachment attachment, ImageView imageView) {
+ imageView.setBackgroundColor(StyledAttributes.getColor(context, R.attr.color_background_tertiary));
+ imageView.setImageAlpha(Math.round(StyledAttributes.getFloat(context, R.attr.icon_alpha) * 255));
+ imageView.setImageDrawable(StyledAttributes.getDrawable(context, getImageAttr(attachment)));
+ }
+
+ private static boolean cancelPotentialWork(Attachment attachment, ImageView imageView) {
+ final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
+
+ if (bitmapWorkerTask != null) {
+ final Attachment oldAttachment = bitmapWorkerTask.attachment;
+ if (oldAttachment == null || !oldAttachment.equals(attachment)) {
+ bitmapWorkerTask.cancel(true);
+ } else {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
+ if (imageView != null) {
+ final Drawable drawable = imageView.getDrawable();
+ if (drawable instanceof AsyncDrawable) {
+ final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
+ return asyncDrawable.getBitmapWorkerTask();
+ }
+ }
+ return null;
+ }
+
+ @NonNull
+ @Override
+ public MediaViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
+ MediaBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.media, parent, false);
+ return new MediaViewHolder(binding);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull MediaViewHolder holder, int position) {
+ final Attachment attachment = attachments.get(position);
+ if (attachment.renderThumbnail()) {
+ holder.binding.media.setImageAlpha(255);
+ loadPreview(attachment, holder.binding.media);
+ } else {
+ cancelPotentialWork(attachment, holder.binding.media);
+ renderPreview(activity, attachment, holder.binding.media);
+ }
+ holder.binding.media.setOnClickListener(v -> ViewUtil.view(activity, attachment));
+ }
+
+ public void setAttachments(List<Attachment> attachments) {
+ this.attachments.clear();
+ this.attachments.addAll(attachments);
+ notifyDataSetChanged();
+ }
+
+ private void setMediaSize(int mediaSize) {
+ this.mediaSize = mediaSize;
+ }
+
+ private void loadPreview(Attachment attachment, ImageView imageView) {
+ if (cancelPotentialWork(attachment, imageView)) {
+ final Bitmap bm = activity.xmppConnectionService.getFileBackend().getPreviewForUri(attachment, mediaSize, true);
+ if (bm != null) {
+ cancelPotentialWork(attachment, imageView);
+ imageView.setImageBitmap(bm);
+ imageView.setBackgroundColor(0x00000000);
+ } else {
+ imageView.setBackgroundColor(0xff333333);
+ imageView.setImageDrawable(null);
+ final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
+ final AsyncDrawable asyncDrawable = new AsyncDrawable(activity.getResources(), null, task);
+ imageView.setImageDrawable(asyncDrawable);
+ try {
+ task.execute(attachment);
+ } catch (final RejectedExecutionException ignored) {
+ }
+ }
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ return attachments.size();
+ }
+
+ static class AsyncDrawable extends BitmapDrawable {
+ private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
+
+ AsyncDrawable(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) {
+ super(res, bitmap);
+ bitmapWorkerTaskReference = new WeakReference<>(bitmapWorkerTask);
+ }
+
+ BitmapWorkerTask getBitmapWorkerTask() {
+ return bitmapWorkerTaskReference.get();
+ }
+ }
+
+ class MediaViewHolder extends RecyclerView.ViewHolder {
+
+ private final MediaBinding binding;
+
+ MediaViewHolder(MediaBinding binding) {
+ super(binding.getRoot());
+ this.binding = binding;
+ }
+ }
+
+ class BitmapWorkerTask extends AsyncTask<Attachment, Void, Bitmap> {
+ private final WeakReference<ImageView> imageViewReference;
+ private Attachment attachment = null;
+
+ BitmapWorkerTask(ImageView imageView) {
+ imageViewReference = new WeakReference<>(imageView);
+ }
+
+ @Override
+ protected Bitmap doInBackground(Attachment... params) {
+ this.attachment = params[0];
+ return activity.xmppConnectionService.getFileBackend().getPreviewForUri(this.attachment, mediaSize, false);
+ }
+
+ @Override
+ protected void onPostExecute(Bitmap bitmap) {
+ if (bitmap != null && !isCancelled()) {
+ final ImageView imageView = imageViewReference.get();
+ if (imageView != null) {
+ imageView.setImageBitmap(bitmap);
+ imageView.setBackgroundColor(0x00000000);
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/de/pixart/messenger/ui/adapter/MediaPreviewAdapter.java b/src/main/java/de/pixart/messenger/ui/adapter/MediaPreviewAdapter.java
index 9192c6555..ae4c42816 100644
--- a/src/main/java/de/pixart/messenger/ui/adapter/MediaPreviewAdapter.java
+++ b/src/main/java/de/pixart/messenger/ui/adapter/MediaPreviewAdapter.java
@@ -8,7 +8,6 @@ import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
-import android.support.annotation.AttrRes;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
@@ -17,7 +16,6 @@ import android.widget.ImageView;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import java.util.concurrent.RejectedExecutionException;
@@ -26,19 +24,9 @@ import de.pixart.messenger.databinding.MediaPreviewBinding;
import de.pixart.messenger.ui.ConversationFragment;
import de.pixart.messenger.ui.XmppActivity;
import de.pixart.messenger.ui.util.Attachment;
-import de.pixart.messenger.ui.util.StyledAttributes;
public class MediaPreviewAdapter extends RecyclerView.Adapter<MediaPreviewAdapter.MediaPreviewViewHolder> {
- private static final List<String> DOCUMENT_MIMES = Arrays.asList(
- "application/pdf",
- "application/vnd.oasis.opendocument.text",
- "application/msword",
- "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
- "text/x-tex",
- "text/plain"
- );
-
private final ArrayList<Attachment> mediaPreviews = new ArrayList<>();
private final ConversationFragment conversationFragment;
@@ -89,34 +77,7 @@ public class MediaPreviewAdapter extends RecyclerView.Adapter<MediaPreviewAdapte
loadPreview(attachment, holder.binding.mediaPreview);
} else {
cancelPotentialWork(attachment, holder.binding.mediaPreview);
- holder.binding.mediaPreview.setBackgroundColor(StyledAttributes.getColor(context, R.attr.color_background_tertiary));
- holder.binding.mediaPreview.setImageAlpha(Math.round(StyledAttributes.getFloat(context, R.attr.icon_alpha) * 255));
- final @AttrRes int attr;
- if (attachment.getType() == Attachment.Type.LOCATION) {
- attr = R.attr.media_preview_location;
- } else if (attachment.getType() == Attachment.Type.RECORDING) {
- attr = R.attr.media_preview_recording;
- } else {
- final String mime = attachment.getMime();
- if (mime == null) {
- attr = R.attr.media_preview_unknown;
- } else if (mime.startsWith("audio/")) {
- attr = R.attr.media_preview_audio;
- } else if (mime.equals("text/calendar") || (mime.equals("text/x-vcalendar"))) {
- attr = R.attr.media_preview_calendar;
- } else if (mime.equals("text/x-vcard")) {
- attr = R.attr.media_preview_contact;
- } else if (mime.equals("application/vnd.android.package-archive")) {
- attr = R.attr.media_preview_app;
- } else if (mime.equals("application/zip") || mime.equals("application/rar")) {
- attr = R.attr.media_preview_archive;
- } else if (DOCUMENT_MIMES.contains(mime)) {
- attr = R.attr.media_preview_document;
- } else {
- attr = R.attr.media_preview_unknown;
- }
- }
- holder.binding.mediaPreview.setImageDrawable(StyledAttributes.getDrawable(context, attr));
+ MediaAdapter.renderPreview(context, attachment, holder.binding.mediaPreview);
}
holder.binding.deleteButton.setOnClickListener(v -> {
int pos = mediaPreviews.indexOf(attachment);
@@ -166,6 +127,10 @@ public class MediaPreviewAdapter extends RecyclerView.Adapter<MediaPreviewAdapte
return mediaPreviews;
}
+ public void clearPreviews() {
+ this.mediaPreviews.clear();
+ }
+
static class AsyncDrawable extends BitmapDrawable {
private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
@@ -179,11 +144,6 @@ public class MediaPreviewAdapter extends RecyclerView.Adapter<MediaPreviewAdapte
}
}
- public void clearPreviews() {
- this.mediaPreviews.clear();
- }
-
-
class MediaPreviewViewHolder extends RecyclerView.ViewHolder {
private final MediaPreviewBinding binding;
diff --git a/src/main/java/de/pixart/messenger/ui/adapter/MessageAdapter.java b/src/main/java/de/pixart/messenger/ui/adapter/MessageAdapter.java
index efd3b8842..ae124e950 100644
--- a/src/main/java/de/pixart/messenger/ui/adapter/MessageAdapter.java
+++ b/src/main/java/de/pixart/messenger/ui/adapter/MessageAdapter.java
@@ -6,7 +6,6 @@ import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Color;
@@ -29,7 +28,6 @@ import android.text.style.RelativeSizeSpan;
import android.text.style.StyleSpan;
import android.util.Base64;
import android.util.DisplayMetrics;
-import android.util.Log;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
@@ -77,6 +75,7 @@ import de.pixart.messenger.ui.XmppActivity;
import de.pixart.messenger.ui.text.DividerSpan;
import de.pixart.messenger.ui.text.QuoteSpan;
import de.pixart.messenger.ui.util.MyLinkify;
+import de.pixart.messenger.ui.util.ViewUtil;
import de.pixart.messenger.ui.widget.ClickableMovementMethod;
import de.pixart.messenger.ui.widget.CopyTextView;
import de.pixart.messenger.ui.widget.ListSelectionManager;
@@ -1068,31 +1067,10 @@ public class MessageAdapter extends ArrayAdapter<Message> implements CopyTextVie
//ignored
}
}
- Intent openIntent = new Intent(Intent.ACTION_VIEW);
if (mime == null) {
mime = "*/*";
}
- Uri uri;
- try {
- uri = FileBackend.getUriForFile(activity, file);
- } catch (SecurityException e) {
- Log.d(Config.LOGTAG, "No permission to access " + file.getAbsolutePath(), e);
- Toast.makeText(activity, activity.getString(R.string.no_permission_to_access_x, file.getAbsolutePath()), Toast.LENGTH_SHORT).show();
- return;
- }
- openIntent.setDataAndType(uri, mime);
- openIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- PackageManager manager = activity.getPackageManager();
- List<ResolveInfo> info = manager.queryIntentActivities(openIntent, 0);
- if (info.size() == 0) {
- openIntent.setDataAndType(uri,"*/*");
- }
- try {
- getContext().startActivity(openIntent);
- activity.overridePendingTransition(R.animator.fade_in, R.animator.fade_out);
- } catch (ActivityNotFoundException e) {
- Toast.makeText(activity, R.string.no_application_found_to_open_file, Toast.LENGTH_SHORT).show();
- }
+ ViewUtil.view(activity, file, mime);
}
public void showLocation(Message message) {
diff --git a/src/main/java/de/pixart/messenger/ui/interfaces/OnMediaLoaded.java b/src/main/java/de/pixart/messenger/ui/interfaces/OnMediaLoaded.java
new file mode 100644
index 000000000..0441be96d
--- /dev/null
+++ b/src/main/java/de/pixart/messenger/ui/interfaces/OnMediaLoaded.java
@@ -0,0 +1,10 @@
+package de.pixart.messenger.ui.interfaces;
+
+import java.util.List;
+
+import de.pixart.messenger.ui.util.Attachment;
+
+public interface OnMediaLoaded {
+
+ void onMediaLoaded(List<Attachment> attachments);
+} \ No newline at end of file
diff --git a/src/main/java/de/pixart/messenger/ui/util/Attachment.java b/src/main/java/de/pixart/messenger/ui/util/Attachment.java
index f11efd0d1..96159c1bd 100644
--- a/src/main/java/de/pixart/messenger/ui/util/Attachment.java
+++ b/src/main/java/de/pixart/messenger/ui/util/Attachment.java
@@ -37,6 +37,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
+import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -61,12 +62,21 @@ public class Attachment implements Parcelable {
private final Type type;
private final UUID uuid;
private final String mime;
+
Attachment(Parcel in) {
uri = in.readParcelable(Uri.class.getClassLoader());
mime = in.readString();
uuid = UUID.fromString(in.readString());
type = Type.valueOf(in.readString());
}
+
+ private Attachment(UUID uuid, Uri uri, Type type, String mime) {
+ this.uri = uri;
+ this.type = type;
+ this.mime = mime;
+ this.uuid = uuid;
+ }
+
private Attachment(Uri uri, Type type, String mime) {
this.uri = uri;
this.type = type;
@@ -88,6 +98,10 @@ public class Attachment implements Parcelable {
return attachments;
}
+ public static Attachment of(UUID uuid, final File file, String mime) {
+ return new Attachment(uuid, Uri.fromFile(file), mime != null && (mime.startsWith("image/") || mime.startsWith("video/")) ? Type.IMAGE : Type.FILE, mime);
+ }
+
public static List<Attachment> extractAttachments(final Context context, final Intent intent, Type type) {
List<Attachment> uris = new ArrayList<>();
if (intent == null) {
diff --git a/src/main/java/de/pixart/messenger/ui/util/GridManager.java b/src/main/java/de/pixart/messenger/ui/util/GridManager.java
new file mode 100644
index 000000000..717fef526
--- /dev/null
+++ b/src/main/java/de/pixart/messenger/ui/util/GridManager.java
@@ -0,0 +1,71 @@
+package de.pixart.messenger.ui.util;
+
+import android.content.Context;
+import android.support.annotation.DimenRes;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.util.Log;
+import android.view.ViewTreeObserver;
+
+import de.pixart.messenger.Config;
+import de.pixart.messenger.ui.adapter.MediaAdapter;
+
+public class GridManager {
+
+ public static void setupLayoutManager(final Context context, RecyclerView recyclerView, @DimenRes int desiredSize) {
+ int maxWidth = context.getResources().getDisplayMetrics().widthPixels;
+ ColumnInfo columnInfo = calculateColumnCount(context, maxWidth, desiredSize);
+ Log.d(Config.LOGTAG, "preliminary count=" + columnInfo.count);
+ MediaAdapter.setMediaSize(recyclerView, columnInfo.width);
+ recyclerView.setLayoutManager(new GridLayoutManager(context, columnInfo.count));
+ recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ recyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ final ColumnInfo columnInfo = calculateColumnCount(context, recyclerView.getMeasuredWidth(), desiredSize);
+ Log.d(Config.LOGTAG, "final count " + columnInfo.count);
+ if (recyclerView.getAdapter().getItemCount() != 0) {
+ Log.e(Config.LOGTAG, "adapter already has items; just go with it now");
+ return;
+ }
+ setupLayoutManagerInternal(recyclerView, columnInfo);
+ MediaAdapter.setMediaSize(recyclerView, columnInfo.width);
+ }
+ });
+ }
+
+ private static void setupLayoutManagerInternal(RecyclerView recyclerView, final ColumnInfo columnInfo) {
+ RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
+ if (layoutManager instanceof GridLayoutManager) {
+ ((GridLayoutManager) layoutManager).setSpanCount(columnInfo.count);
+ }
+ }
+
+ private static ColumnInfo calculateColumnCount(Context context, int availableWidth, @DimenRes int desiredSize) {
+ final float desiredWidth = context.getResources().getDimension(desiredSize);
+ final int columns = Math.round(availableWidth / desiredWidth);
+ final int realWidth = availableWidth / columns;
+ Log.d(Config.LOGTAG, "desired=" + desiredWidth + " real=" + realWidth);
+ return new ColumnInfo(columns, realWidth);
+ }
+
+ public static int getCurrentColumnCount(RecyclerView recyclerView) {
+ RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
+ if (layoutManager instanceof GridLayoutManager) {
+ return ((GridLayoutManager) layoutManager).getSpanCount();
+ } else {
+ return 0;
+ }
+ }
+
+ public static class ColumnInfo {
+ private final int count;
+ private final int width;
+
+ private ColumnInfo(int count, int width) {
+ this.count = count;
+ this.width = width;
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/de/pixart/messenger/ui/util/ViewUtil.java b/src/main/java/de/pixart/messenger/ui/util/ViewUtil.java
new file mode 100644
index 000000000..2442df8dc
--- /dev/null
+++ b/src/main/java/de/pixart/messenger/ui/util/ViewUtil.java
@@ -0,0 +1,50 @@
+package de.pixart.messenger.ui.util;
+
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.util.Log;
+import android.widget.Toast;
+
+import java.io.File;
+import java.util.List;
+
+import de.pixart.messenger.Config;
+import de.pixart.messenger.R;
+import de.pixart.messenger.persistance.FileBackend;
+
+public class ViewUtil {
+
+ public static void view(Context context, Attachment attachment) {
+ File file = new File(attachment.getUri().getPath());
+ final String mime = attachment.getMime() == null ? "*/*" : attachment.getMime();
+ view(context, file, mime);
+ }
+
+ public static void view(Context context, File file, String mime) {
+ Intent openIntent = new Intent(Intent.ACTION_VIEW);
+ Uri uri;
+ try {
+ uri = FileBackend.getUriForFile(context, file);
+ } catch (SecurityException e) {
+ Log.d(Config.LOGTAG, "No permission to access " + file.getAbsolutePath(), e);
+ Toast.makeText(context, context.getString(R.string.no_permission_to_access_x, file.getAbsolutePath()), Toast.LENGTH_SHORT).show();
+ return;
+ }
+ openIntent.setDataAndType(uri, mime);
+ openIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ PackageManager manager = context.getPackageManager();
+ List<ResolveInfo> info = manager.queryIntentActivities(openIntent, 0);
+ if (info.size() == 0) {
+ openIntent.setDataAndType(uri, "*/*");
+ }
+ try {
+ context.startActivity(openIntent);
+ } catch (ActivityNotFoundException e) {
+ Toast.makeText(context, R.string.no_application_found_to_open_file, Toast.LENGTH_SHORT).show();
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/de/pixart/messenger/ui/widget/SquareFrameLayout.java b/src/main/java/de/pixart/messenger/ui/widget/SquareFrameLayout.java
new file mode 100644
index 000000000..4d2fcf92d
--- /dev/null
+++ b/src/main/java/de/pixart/messenger/ui/widget/SquareFrameLayout.java
@@ -0,0 +1,25 @@
+package de.pixart.messenger.ui.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+
+public class SquareFrameLayout extends FrameLayout {
+ public SquareFrameLayout(Context context) {
+ super(context);
+ }
+
+ public SquareFrameLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public SquareFrameLayout(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ //noinspection SuspiciousNameCombination
+ super.onMeasure(widthMeasureSpec, widthMeasureSpec);
+ }
+} \ No newline at end of file
diff --git a/src/main/res/layout/activity_contact_details.xml b/src/main/res/layout/activity_contact_details.xml
index dd3ff2c31..64e296c24 100644
--- a/src/main/res/layout/activity_contact_details.xml
+++ b/src/main/res/layout/activity_contact_details.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<layout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:layout_width="match_parent"
@@ -102,8 +101,7 @@
android:layout_marginBottom="4dp"
android:layout_marginLeft="-2dp"
android:layout_marginTop="4dp"
- android:orientation="horizontal">
- </com.wefika.flowlayout.FlowLayout>
+ android:orientation="horizontal"></com.wefika.flowlayout.FlowLayout>
<TextView
android:id="@+id/details_lastseen"
@@ -235,6 +233,52 @@
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
+ android:id="@+id/media_wrapper"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/activity_vertical_margin"
+ android:layout_marginLeft="@dimen/activity_horizontal_margin"
+ android:layout_marginRight="@dimen/activity_horizontal_margin"
+ android:layout_marginTop="@dimen/activity_vertical_margin">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <android.support.v7.widget.RecyclerView
+ android:id="@+id/media"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="-2dp"
+ android:layout_marginStart="-2dp"
+ android:orientation="horizontal"
+ android:paddingBottom="@dimen/card_padding_list"
+ android:paddingEnd="@dimen/card_padding_regular"
+ android:paddingStart="@dimen/card_padding_regular"
+ android:paddingTop="@dimen/card_padding_regular" />
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="end"
+ android:orientation="horizontal">
+
+ <Button
+ android:id="@+id/show_media"
+ style="@style/Widget.Conversations.Button.Borderless"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minWidth="0dp"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:text="@string/show_media"
+ android:textColor="?attr/colorAccent" />
+ </LinearLayout>
+ </LinearLayout>
+ </android.support.v7.widget.CardView>
+
+ <android.support.v7.widget.CardView
android:id="@+id/keys_wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -254,7 +298,7 @@
android:layout_height="wrap_content"
android:divider="?android:dividerHorizontal"
android:orientation="vertical"
- android:padding="@dimen/card_padding_list"></LinearLayout>
+ android:padding="@dimen/card_padding_list" />
<LinearLayout
android:layout_width="wrap_content"
diff --git a/src/main/res/layout/activity_muc_details.xml b/src/main/res/layout/activity_muc_details.xml
index 2a450f964..8a30fdcf4 100644
--- a/src/main/res/layout/activity_muc_details.xml
+++ b/src/main/res/layout/activity_muc_details.xml
@@ -278,6 +278,52 @@
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
+ android:id="@+id/media_wrapper"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/activity_vertical_margin"
+ android:layout_marginLeft="@dimen/activity_horizontal_margin"
+ android:layout_marginRight="@dimen/activity_horizontal_margin"
+ android:layout_marginTop="@dimen/activity_vertical_margin">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <android.support.v7.widget.RecyclerView
+ android:id="@+id/media"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="-2dp"
+ android:layout_marginStart="-2dp"
+ android:orientation="horizontal"
+ android:paddingBottom="@dimen/card_padding_list"
+ android:paddingEnd="@dimen/card_padding_regular"
+ android:paddingStart="@dimen/card_padding_regular"
+ android:paddingTop="@dimen/card_padding_regular" />
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="end"
+ android:orientation="horizontal">
+
+ <Button
+ android:id="@+id/show_media"
+ style="@style/Widget.Conversations.Button.Borderless"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minWidth="0dp"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:text="@string/show_media"
+ android:textColor="?attr/colorAccent" />
+ </LinearLayout>
+ </LinearLayout>
+ </android.support.v7.widget.CardView>
+
+ <android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/activity_vertical_margin"
diff --git a/src/main/res/layout/media.xml b/src/main/res/layout/media.xml
new file mode 100644
index 000000000..f95ddeda3
--- /dev/null
+++ b/src/main/res/layout/media.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <de.pixart.messenger.ui.widget.SquareFrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="2dp">
+
+ <ImageView
+ android:id="@+id/media"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/black54"
+ android:scaleType="centerInside" />
+ </de.pixart.messenger.ui.widget.SquareFrameLayout>
+</layout> \ No newline at end of file
diff --git a/src/main/res/values/dimens.xml b/src/main/res/values/dimens.xml
index c420781ea..055c492d3 100644
--- a/src/main/res/values/dimens.xml
+++ b/src/main/res/values/dimens.xml
@@ -11,6 +11,7 @@
<dimen name="avatar_item_distance">16dp</dimen>
<dimen name="media_preview_size">80dp</dimen>
+ <dimen name="media_size">64dp</dimen>
<dimen name="toolbar_elevation">4dp</dimen>
<dimen name="publish_avatar_top_margin">8dp</dimen>
@@ -25,6 +26,6 @@
<dimen name="scan_dot_size">8dp</dimen>
<dimen name="background_image_opacity">0.12</dimen>
-
+
<dimen name="rounded_image_border">5dp</dimen>
</resources>
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index e5261bb44..2287687fb 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -824,4 +824,5 @@
<string name="backup_channel_name">Database backup</string>
<string name="app_update_channel_name">App update</string>
<string name="action_group_details">Group details</string>
+ <string name="show_media">Show media</string>
</resources>