mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-19 22:29:53 +01:00
[android] refactor AttachmentCreator to return a single LiveData
This commit is contained in:
@@ -14,7 +14,7 @@ import org.jsoup.UnsupportedMimeTypeException;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.List;
|
import java.util.Collection;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
@@ -34,7 +34,7 @@ class AttachmentCreationTask {
|
|||||||
private final MessagingManager messagingManager;
|
private final MessagingManager messagingManager;
|
||||||
private final ContentResolver contentResolver;
|
private final ContentResolver contentResolver;
|
||||||
private final GroupId groupId;
|
private final GroupId groupId;
|
||||||
private final List<Uri> uris;
|
private final Collection<Uri> uris;
|
||||||
private final boolean needsSize;
|
private final boolean needsSize;
|
||||||
@Nullable
|
@Nullable
|
||||||
private volatile AttachmentCreator attachmentCreator;
|
private volatile AttachmentCreator attachmentCreator;
|
||||||
@@ -44,7 +44,7 @@ class AttachmentCreationTask {
|
|||||||
AttachmentCreationTask(MessagingManager messagingManager,
|
AttachmentCreationTask(MessagingManager messagingManager,
|
||||||
ContentResolver contentResolver,
|
ContentResolver contentResolver,
|
||||||
AttachmentCreator attachmentCreator, GroupId groupId,
|
AttachmentCreator attachmentCreator, GroupId groupId,
|
||||||
List<Uri> uris, boolean needsSize) {
|
Collection<Uri> uris, boolean needsSize) {
|
||||||
this.messagingManager = messagingManager;
|
this.messagingManager = messagingManager;
|
||||||
this.contentResolver = contentResolver;
|
this.contentResolver = contentResolver;
|
||||||
this.groupId = groupId;
|
this.groupId = groupId;
|
||||||
|
|||||||
@@ -24,14 +24,14 @@ import java.io.IOException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
import static org.briarproject.briar.android.util.UiUtils.observeForeverOnce;
|
||||||
import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_IMAGE_SIZE;
|
import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_IMAGE_SIZE;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -45,14 +45,12 @@ public class AttachmentCreator {
|
|||||||
private final MessagingManager messagingManager;
|
private final MessagingManager messagingManager;
|
||||||
private final AttachmentRetriever retriever;
|
private final AttachmentRetriever retriever;
|
||||||
|
|
||||||
// store unsent items separately, as LiveData might not return latest value
|
private final CopyOnWriteArrayList<Uri> uris = new CopyOnWriteArrayList<>();
|
||||||
private final Map<Uri, AttachmentItem> unsentItems =
|
private final CopyOnWriteArrayList<AttachmentItemResult> itemResults =
|
||||||
new ConcurrentHashMap<>();
|
new CopyOnWriteArrayList<>();
|
||||||
private final Map<Uri, MutableLiveData<AttachmentItemResult>>
|
|
||||||
liveDataResult = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private MutableLiveData<Boolean> liveDataFinished = null;
|
private volatile MutableLiveData<AttachmentResult> result = null;
|
||||||
@Nullable
|
@Nullable
|
||||||
private AttachmentCreationTask task;
|
private AttachmentCreationTask task;
|
||||||
|
|
||||||
@@ -65,56 +63,49 @@ public class AttachmentCreator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
public AttachmentResult storeAttachments(GroupId groupId,
|
public LiveData<AttachmentResult> storeAttachments(
|
||||||
Collection<Uri> uris, boolean restart) {
|
LiveData<GroupId> groupId, Collection<Uri> newUris, boolean restart) {
|
||||||
List<LiveData<AttachmentItemResult>> itemResults = new ArrayList<>();
|
MutableLiveData<AttachmentResult> result;
|
||||||
if (restart) {
|
if (restart) {
|
||||||
// This can happen due to configuration changes.
|
// This can happen due to configuration changes.
|
||||||
// So don't create new attachments, if we have (or creating) them.
|
// So don't create new attachments. They are already being created
|
||||||
// Instead, re-subscribe to the existing LiveData.
|
// and returned by the existing LiveData.
|
||||||
if (task == null || isNotStoring()) throw new AssertionError();
|
result = this.result;
|
||||||
for (Uri uri : uris) {
|
if (task == null || uris.isEmpty() || result == null)
|
||||||
// We don't want to expose mutable(!) LiveData
|
throw new IllegalStateException();
|
||||||
LiveData<AttachmentItemResult> liveData =
|
// A task is already running. It will update the result LiveData.
|
||||||
liveDataResult.get(uri);
|
// So nothing more to do here.
|
||||||
if (liveData == null) throw new IllegalStateException();
|
|
||||||
itemResults.add(liveData);
|
|
||||||
}
|
|
||||||
if (liveDataFinished == null) throw new IllegalStateException();
|
|
||||||
} else {
|
} else {
|
||||||
if (task != null && isNotStoring()) throw new AssertionError();
|
if (this.result != null || !uris.isEmpty())
|
||||||
List<Uri> urisToStore = new ArrayList<>();
|
throw new IllegalStateException();
|
||||||
for (Uri uri : uris) {
|
result = new MutableLiveData<>();
|
||||||
urisToStore.add(uri);
|
this.result = result;
|
||||||
MutableLiveData<AttachmentItemResult> liveData =
|
uris.addAll(newUris);
|
||||||
new MutableLiveData<>();
|
observeForeverOnce(groupId, id -> {
|
||||||
liveDataResult.put(uri, liveData);
|
if (id == null) throw new IllegalStateException();
|
||||||
itemResults.add(liveData);
|
boolean needsSize = uris.size() == 1;
|
||||||
}
|
task = new AttachmentCreationTask(messagingManager,
|
||||||
boolean needsSize = uris.size() == 1;
|
app.getContentResolver(), this, id, uris, needsSize);
|
||||||
task = new AttachmentCreationTask(messagingManager,
|
ioExecutor.execute(() -> task.storeAttachments());
|
||||||
app.getContentResolver(), this, groupId, urisToStore,
|
});
|
||||||
needsSize);
|
|
||||||
ioExecutor.execute(() -> task.storeAttachments());
|
|
||||||
liveDataFinished = new MutableLiveData<>();
|
|
||||||
}
|
}
|
||||||
return new AttachmentResult(itemResults, liveDataFinished);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@IoExecutor
|
@IoExecutor
|
||||||
void onAttachmentHeaderReceived(Uri uri, AttachmentHeader h,
|
void onAttachmentHeaderReceived(Uri uri, AttachmentHeader h,
|
||||||
boolean needsSize) {
|
boolean needsSize) {
|
||||||
|
MutableLiveData<AttachmentResult> result = this.result;
|
||||||
|
if (result == null) return;
|
||||||
// get and cache AttachmentItem for ImagePreview
|
// get and cache AttachmentItem for ImagePreview
|
||||||
try {
|
try {
|
||||||
Attachment a = retriever.getMessageAttachment(h);
|
Attachment a = retriever.getMessageAttachment(h);
|
||||||
AttachmentItem item = retriever.getAttachmentItem(h, a, needsSize);
|
AttachmentItem item = retriever.getAttachmentItem(h, a, needsSize);
|
||||||
if (item.hasError()) throw new IOException();
|
if (item.hasError()) throw new IOException();
|
||||||
unsentItems.put(uri, item);
|
AttachmentItemResult itemResult =
|
||||||
MutableLiveData<AttachmentItemResult> result =
|
new AttachmentItemResult(uri, item);
|
||||||
liveDataResult.get(uri);
|
itemResults.add(itemResult);
|
||||||
if (result != null) { // might have been cleared on UiThread
|
result.postValue(new AttachmentResult(itemResults, false));
|
||||||
result.postValue(new AttachmentItemResult(uri, item));
|
|
||||||
}
|
|
||||||
} catch (IOException | DbException e) {
|
} catch (IOException | DbException e) {
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
onAttachmentError(uri, e);
|
onAttachmentError(uri, e);
|
||||||
@@ -123,6 +114,9 @@ public class AttachmentCreator {
|
|||||||
|
|
||||||
@IoExecutor
|
@IoExecutor
|
||||||
void onAttachmentError(Uri uri, Throwable t) {
|
void onAttachmentError(Uri uri, Throwable t) {
|
||||||
|
MutableLiveData<AttachmentResult> result = this.result;
|
||||||
|
if (result == null) return;
|
||||||
|
// get error message
|
||||||
String errorMsg;
|
String errorMsg;
|
||||||
if (t instanceof UnsupportedMimeTypeException) {
|
if (t instanceof UnsupportedMimeTypeException) {
|
||||||
String mimeType = ((UnsupportedMimeTypeException) t).getMimeType();
|
String mimeType = ((UnsupportedMimeTypeException) t).getMimeType();
|
||||||
@@ -134,23 +128,29 @@ public class AttachmentCreator {
|
|||||||
} else {
|
} else {
|
||||||
errorMsg = null; // generic error
|
errorMsg = null; // generic error
|
||||||
}
|
}
|
||||||
MutableLiveData<AttachmentItemResult> result = liveDataResult.get(uri);
|
AttachmentItemResult itemResult =
|
||||||
if (result != null)
|
new AttachmentItemResult(uri, errorMsg);
|
||||||
result.postValue(new AttachmentItemResult(errorMsg));
|
itemResults.add(itemResult);
|
||||||
|
result.postValue(new AttachmentResult(itemResults, false));
|
||||||
// expect to receive a cancel from the UI
|
// expect to receive a cancel from the UI
|
||||||
}
|
}
|
||||||
|
|
||||||
@IoExecutor
|
@IoExecutor
|
||||||
void onAttachmentCreationFinished() {
|
void onAttachmentCreationFinished() {
|
||||||
if (liveDataFinished != null) liveDataFinished.postValue(true);
|
if (uris.size() != itemResults.size())
|
||||||
|
throw new IllegalStateException();
|
||||||
|
MutableLiveData<AttachmentResult> result = this.result;
|
||||||
|
if (result == null) return;
|
||||||
|
result.postValue(new AttachmentResult(itemResults, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
public List<AttachmentHeader> getAttachmentHeadersForSending() {
|
public List<AttachmentHeader> getAttachmentHeadersForSending() {
|
||||||
List<AttachmentHeader> headers =
|
List<AttachmentHeader> headers = new ArrayList<>(itemResults.size());
|
||||||
new ArrayList<>(unsentItems.values().size());
|
for (AttachmentItemResult itemResult : itemResults) {
|
||||||
for (AttachmentItem item : unsentItems.values()) {
|
// check if we are trying to send attachment items with errors
|
||||||
headers.add(item.getHeader());
|
if (itemResult.getItem() == null) throw new IllegalStateException();
|
||||||
|
headers.add(itemResult.getItem().getHeader());
|
||||||
}
|
}
|
||||||
return headers;
|
return headers;
|
||||||
}
|
}
|
||||||
@@ -161,22 +161,28 @@ public class AttachmentCreator {
|
|||||||
* @param id The MessageId of the sent message.
|
* @param id The MessageId of the sent message.
|
||||||
*/
|
*/
|
||||||
public void onAttachmentsSent(MessageId id) {
|
public void onAttachmentsSent(MessageId id) {
|
||||||
retriever.cachePut(id, new ArrayList<>(unsentItems.values()));
|
List<AttachmentItem> items = new ArrayList<>(itemResults.size());
|
||||||
|
for (AttachmentItemResult itemResult : itemResults) {
|
||||||
|
// check if we are trying to send attachment items with errors
|
||||||
|
if (itemResult.getItem() == null) throw new IllegalStateException();
|
||||||
|
items.add(itemResult.getItem());
|
||||||
|
}
|
||||||
|
retriever.cachePut(id, items);
|
||||||
resetState();
|
resetState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Needs to be called when created attachments will not be sent anymore.
|
||||||
|
*/
|
||||||
@UiThread
|
@UiThread
|
||||||
public void cancel() {
|
public void cancel() {
|
||||||
if (task == null) throw new AssertionError();
|
if (task == null) throw new AssertionError();
|
||||||
task.cancel();
|
task.cancel();
|
||||||
// let observers know that they can remove themselves
|
// let observers know that they can remove themselves
|
||||||
for (MutableLiveData<AttachmentItemResult> liveData : liveDataResult
|
MutableLiveData<AttachmentResult> result = this.result;
|
||||||
.values()) {
|
if (result != null) {
|
||||||
if (liveData.getValue() == null) {
|
result.setValue(null);
|
||||||
liveData.setValue(null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (liveDataFinished != null) liveDataFinished.setValue(false);
|
|
||||||
deleteUnsentAttachments();
|
deleteUnsentAttachments();
|
||||||
resetState();
|
resetState();
|
||||||
}
|
}
|
||||||
@@ -184,20 +190,24 @@ public class AttachmentCreator {
|
|||||||
@UiThread
|
@UiThread
|
||||||
private void resetState() {
|
private void resetState() {
|
||||||
task = null;
|
task = null;
|
||||||
liveDataResult.clear();
|
uris.clear();
|
||||||
liveDataFinished = null;
|
itemResults.clear();
|
||||||
unsentItems.clear();
|
result = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
public void deleteUnsentAttachments() {
|
public void deleteUnsentAttachments() {
|
||||||
// Make a copy for the IoExecutor as we clear the unsentItems soon
|
// Make a copy for the IoExecutor as we clear the itemResults soon
|
||||||
List<AttachmentItem> itemsToDelete =
|
List<AttachmentHeader> headers = new ArrayList<>(itemResults.size());
|
||||||
new ArrayList<>(unsentItems.values());
|
for (AttachmentItemResult itemResult : itemResults) {
|
||||||
|
// check if we are trying to send attachment items with errors
|
||||||
|
if (itemResult.getItem() != null)
|
||||||
|
headers.add(itemResult.getItem().getHeader());
|
||||||
|
}
|
||||||
ioExecutor.execute(() -> {
|
ioExecutor.execute(() -> {
|
||||||
for (AttachmentItem item : itemsToDelete) {
|
for (AttachmentHeader header : headers) {
|
||||||
try {
|
try {
|
||||||
messagingManager.removeAttachment(item.getHeader());
|
messagingManager.removeAttachment(header);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
@@ -205,8 +215,4 @@ public class AttachmentCreator {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isNotStoring() {
|
|
||||||
return liveDataFinished == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,26 +11,24 @@ import javax.annotation.concurrent.Immutable;
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class AttachmentItemResult {
|
public class AttachmentItemResult {
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private final Uri uri;
|
private final Uri uri;
|
||||||
@Nullable
|
@Nullable
|
||||||
private final AttachmentItem item;
|
private final AttachmentItem item;
|
||||||
@Nullable
|
@Nullable
|
||||||
private final String errorMsg;
|
private final String errorMsg;
|
||||||
|
|
||||||
public AttachmentItemResult(Uri uri, AttachmentItem item) {
|
AttachmentItemResult(Uri uri, AttachmentItem item) {
|
||||||
this.uri = uri;
|
this.uri = uri;
|
||||||
this.item = item;
|
this.item = item;
|
||||||
this.errorMsg = null;
|
this.errorMsg = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AttachmentItemResult(@Nullable String errorMsg) {
|
AttachmentItemResult(Uri uri, @Nullable String errorMsg) {
|
||||||
this.uri = null;
|
this.uri = uri;
|
||||||
this.item = null;
|
this.item = null;
|
||||||
this.errorMsg = errorMsg;
|
this.errorMsg = errorMsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public Uri getUri() {
|
public Uri getUri() {
|
||||||
return uri;
|
return uri;
|
||||||
}
|
}
|
||||||
@@ -40,8 +38,8 @@ public class AttachmentItemResult {
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isError() {
|
public boolean hasError() {
|
||||||
return errorMsg != null;
|
return item == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.briar.android.attachment;
|
package org.briarproject.briar.android.attachment;
|
||||||
|
|
||||||
|
import android.arch.lifecycle.LiveData;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
|
|
||||||
@@ -11,7 +12,8 @@ import java.util.List;
|
|||||||
@UiThread
|
@UiThread
|
||||||
public interface AttachmentManager {
|
public interface AttachmentManager {
|
||||||
|
|
||||||
AttachmentResult storeAttachments(Collection<Uri> uri, boolean restart);
|
LiveData<AttachmentResult> storeAttachments(Collection<Uri> uri,
|
||||||
|
boolean restart);
|
||||||
|
|
||||||
List<AttachmentHeader> getAttachmentHeadersForSending();
|
List<AttachmentHeader> getAttachmentHeadersForSending();
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package org.briarproject.briar.android.attachment;
|
package org.briarproject.briar.android.attachment;
|
||||||
|
|
||||||
import android.arch.lifecycle.LiveData;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -12,21 +10,20 @@ import javax.annotation.concurrent.Immutable;
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class AttachmentResult {
|
public class AttachmentResult {
|
||||||
|
|
||||||
private final Collection<LiveData<AttachmentItemResult>> itemResults;
|
private final Collection<AttachmentItemResult> itemResults;
|
||||||
private final LiveData<Boolean> finished;
|
private final boolean finished;
|
||||||
|
|
||||||
public AttachmentResult(
|
public AttachmentResult(Collection<AttachmentItemResult> itemResults,
|
||||||
Collection<LiveData<AttachmentItemResult>> itemResults,
|
boolean finished) {
|
||||||
LiveData<Boolean> finished) {
|
|
||||||
this.itemResults = itemResults;
|
this.itemResults = itemResults;
|
||||||
this.finished = finished;
|
this.finished = finished;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<LiveData<AttachmentItemResult>> getItemResults() {
|
public Collection<AttachmentItemResult> getItemResults() {
|
||||||
return itemResults;
|
return itemResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LiveData<Boolean> getFinished() {
|
public boolean isFinished() {
|
||||||
return finished;
|
return finished;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ import static org.briarproject.bramble.util.LogUtils.logException;
|
|||||||
import static org.briarproject.bramble.util.LogUtils.now;
|
import static org.briarproject.bramble.util.LogUtils.now;
|
||||||
import static org.briarproject.briar.android.attachment.AttachmentDimensions.getAttachmentDimensions;
|
import static org.briarproject.briar.android.attachment.AttachmentDimensions.getAttachmentDimensions;
|
||||||
import static org.briarproject.briar.android.settings.SettingsFragment.SETTINGS_NAMESPACE;
|
import static org.briarproject.briar.android.settings.SettingsFragment.SETTINGS_NAMESPACE;
|
||||||
|
import static org.briarproject.briar.android.util.UiUtils.observeForeverOnce;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class ConversationViewModel extends AndroidViewModel
|
public class ConversationViewModel extends AndroidViewModel
|
||||||
@@ -80,13 +81,12 @@ public class ConversationViewModel extends AndroidViewModel
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private ContactId contactId = null;
|
private ContactId contactId = null;
|
||||||
@Nullable
|
|
||||||
private volatile GroupId messagingGroupId = null;
|
|
||||||
private final MutableLiveData<Contact> contact = new MutableLiveData<>();
|
private final MutableLiveData<Contact> contact = new MutableLiveData<>();
|
||||||
private final LiveData<AuthorId> contactAuthorId =
|
private final LiveData<AuthorId> contactAuthorId =
|
||||||
Transformations.map(contact, c -> c.getAuthor().getId());
|
Transformations.map(contact, c -> c.getAuthor().getId());
|
||||||
private final LiveData<String> contactName =
|
private final LiveData<String> contactName =
|
||||||
Transformations.map(contact, UiUtils::getContactDisplayName);
|
Transformations.map(contact, UiUtils::getContactDisplayName);
|
||||||
|
private final LiveData<GroupId> messagingGroupId;
|
||||||
private final MutableLiveData<Boolean> imageSupport =
|
private final MutableLiveData<Boolean> imageSupport =
|
||||||
new MutableLiveData<>();
|
new MutableLiveData<>();
|
||||||
private final MutableLiveEvent<Boolean> showImageOnboarding =
|
private final MutableLiveEvent<Boolean> showImageOnboarding =
|
||||||
@@ -120,6 +120,8 @@ public class ConversationViewModel extends AndroidViewModel
|
|||||||
getAttachmentDimensions(application.getResources()));
|
getAttachmentDimensions(application.getResources()));
|
||||||
this.attachmentCreator = new AttachmentCreator(getApplication(),
|
this.attachmentCreator = new AttachmentCreator(getApplication(),
|
||||||
ioExecutor, messagingManager, attachmentRetriever);
|
ioExecutor, messagingManager, attachmentRetriever);
|
||||||
|
messagingGroupId = Transformations
|
||||||
|
.map(contact, c -> messagingManager.getContactGroup(c).getId());
|
||||||
contactDeleted.setValue(false);
|
contactDeleted.setValue(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,9 +152,6 @@ public class ConversationViewModel extends AndroidViewModel
|
|||||||
contact.postValue(c);
|
contact.postValue(c);
|
||||||
logDuration(LOG, "Loading contact", start);
|
logDuration(LOG, "Loading contact", start);
|
||||||
start = now();
|
start = now();
|
||||||
messagingGroupId = messagingManager.getContactGroup(c).getId();
|
|
||||||
logDuration(LOG, "Load conversation GroupId", start);
|
|
||||||
start = now();
|
|
||||||
checkFeaturesAndOnboarding(contactId);
|
checkFeaturesAndOnboarding(contactId);
|
||||||
logDuration(LOG, "Checking for image support", start);
|
logDuration(LOG, "Checking for image support", start);
|
||||||
} catch (NoSuchContactException e) {
|
} catch (NoSuchContactException e) {
|
||||||
@@ -189,18 +188,20 @@ public class ConversationViewModel extends AndroidViewModel
|
|||||||
|
|
||||||
void sendMessage(@Nullable String text,
|
void sendMessage(@Nullable String text,
|
||||||
List<AttachmentHeader> attachmentHeaders, long timestamp) {
|
List<AttachmentHeader> attachmentHeaders, long timestamp) {
|
||||||
GroupId groupId = messagingGroupId;
|
// messagingGroupId is loaded with the contact
|
||||||
if (groupId == null) throw new IllegalStateException();
|
observeForeverOnce(messagingGroupId, groupId -> {
|
||||||
createMessage(groupId, text, attachmentHeaders, timestamp);
|
if (groupId == null) throw new IllegalStateException();
|
||||||
|
createMessage(groupId, text, attachmentHeaders, timestamp);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@UiThread
|
@UiThread
|
||||||
public AttachmentResult storeAttachments(Collection<Uri> uris,
|
public LiveData<AttachmentResult> storeAttachments(Collection<Uri> uris,
|
||||||
boolean restart) {
|
boolean restart) {
|
||||||
GroupId groupId = messagingGroupId;
|
// messagingGroupId is loaded with the contact
|
||||||
if (groupId == null) throw new IllegalStateException();
|
return attachmentCreator
|
||||||
return attachmentCreator.storeAttachments(groupId, uris, restart);
|
.storeAttachments(messagingGroupId, uris, restart);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import java.util.Collection;
|
|||||||
|
|
||||||
import static android.content.Context.LAYOUT_INFLATER_SERVICE;
|
import static android.content.Context.LAYOUT_INFLATER_SERVICE;
|
||||||
import static android.support.v4.content.ContextCompat.getColor;
|
import static android.support.v4.content.ContextCompat.getColor;
|
||||||
|
import static android.support.v7.widget.RecyclerView.NO_POSITION;
|
||||||
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
||||||
import static java.util.Objects.requireNonNull;
|
import static java.util.Objects.requireNonNull;
|
||||||
|
|
||||||
@@ -75,7 +76,10 @@ public class ImagePreview extends ConstraintLayout {
|
|||||||
void loadPreviewImage(AttachmentItemResult result) {
|
void loadPreviewImage(AttachmentItemResult result) {
|
||||||
ImagePreviewAdapter adapter =
|
ImagePreviewAdapter adapter =
|
||||||
((ImagePreviewAdapter) imageList.getAdapter());
|
((ImagePreviewAdapter) imageList.getAdapter());
|
||||||
requireNonNull(adapter).loadItemPreview(result);
|
int pos = requireNonNull(adapter).loadItemPreview(result);
|
||||||
|
if (pos != NO_POSITION) {
|
||||||
|
imageList.smoothScrollToPosition(pos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ImagePreviewListener {
|
interface ImagePreviewListener {
|
||||||
|
|||||||
@@ -50,14 +50,17 @@ class ImagePreviewAdapter extends Adapter<ImagePreviewViewHolder> {
|
|||||||
return items.size();
|
return items.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadItemPreview(AttachmentItemResult result) {
|
int loadItemPreview(AttachmentItemResult result) {
|
||||||
ImagePreviewItem newItem =
|
ImagePreviewItem newItem = new ImagePreviewItem(result.getUri());
|
||||||
new ImagePreviewItem(requireNonNull(result.getUri()));
|
|
||||||
int pos = items.indexOf(newItem);
|
int pos = items.indexOf(newItem);
|
||||||
if (pos == NO_POSITION) throw new AssertionError();
|
if (pos == NO_POSITION) throw new AssertionError();
|
||||||
ImagePreviewItem item = items.get(pos);
|
ImagePreviewItem item = items.get(pos);
|
||||||
item.setItem(requireNonNull(result.getItem()));
|
if (item.getItem() == null) {
|
||||||
notifyItemChanged(pos, item);
|
item.setItem(requireNonNull(result.getItem()));
|
||||||
|
notifyItemChanged(pos, item);
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
return NO_POSITION;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import org.briarproject.briar.android.attachment.AttachmentResult;
|
|||||||
import org.briarproject.briar.android.view.ImagePreview.ImagePreviewListener;
|
import org.briarproject.briar.android.view.ImagePreview.ImagePreviewListener;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt;
|
import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt;
|
||||||
@@ -172,40 +173,39 @@ public class TextAttachmentController extends TextSendController
|
|||||||
List<ImagePreviewItem> items = ImagePreviewItem.fromUris(imageUris);
|
List<ImagePreviewItem> items = ImagePreviewItem.fromUris(imageUris);
|
||||||
imagePreview.showPreview(items);
|
imagePreview.showPreview(items);
|
||||||
// store attachments and show preview when successful
|
// store attachments and show preview when successful
|
||||||
AttachmentResult result =
|
LiveData<AttachmentResult> result =
|
||||||
attachmentManager.storeAttachments(imageUris, restart);
|
attachmentManager.storeAttachments(imageUris, restart);
|
||||||
for (LiveData<AttachmentItemResult> liveData : result
|
result.observe(imageListener, new Observer<AttachmentResult>() {
|
||||||
.getItemResults()) {
|
|
||||||
onLiveDataReturned(liveData);
|
|
||||||
}
|
|
||||||
result.getFinished().observe(imageListener, new Observer<Boolean>() {
|
|
||||||
@Override
|
@Override
|
||||||
public void onChanged(@Nullable Boolean finished) {
|
public void onChanged(@Nullable AttachmentResult attachmentResult) {
|
||||||
if (finished != null && finished) onAllAttachmentsCreated();
|
if (attachmentResult == null) {
|
||||||
result.getFinished().removeObserver(this);
|
// The fresh LiveData was deliberately set to null.
|
||||||
}
|
// This means that we can stop observing it.
|
||||||
});
|
result.removeObserver(this);
|
||||||
}
|
} else {
|
||||||
|
boolean noError = onNewAttachmentItemResults(
|
||||||
private void onLiveDataReturned(LiveData<AttachmentItemResult> liveData) {
|
attachmentResult.getItemResults());
|
||||||
liveData.observe(imageListener, new Observer<AttachmentItemResult>() {
|
if (noError && attachmentResult.isFinished()) {
|
||||||
@Override
|
onAllAttachmentsCreated();
|
||||||
public void onChanged(@Nullable AttachmentItemResult result) {
|
result.removeObserver(this);
|
||||||
if (result != null) {
|
}
|
||||||
onAttachmentResultReceived(result);
|
|
||||||
}
|
}
|
||||||
liveData.removeObserver(this);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onAttachmentResultReceived(AttachmentItemResult result) {
|
private boolean onNewAttachmentItemResults(
|
||||||
|
Collection<AttachmentItemResult> itemResults) {
|
||||||
if (!loadingUris) throw new AssertionError();
|
if (!loadingUris) throw new AssertionError();
|
||||||
if (result.isError() || result.getUri() == null) {
|
for (AttachmentItemResult result : itemResults) {
|
||||||
onError(result.getErrorMsg());
|
if (result.hasError()) {
|
||||||
} else {
|
onError(result.getErrorMsg());
|
||||||
imagePreview.loadPreviewImage(result);
|
return false;
|
||||||
|
} else {
|
||||||
|
imagePreview.loadPreviewImage(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onAllAttachmentsCreated() {
|
private void onAllAttachmentsCreated() {
|
||||||
|
|||||||
Reference in New Issue
Block a user