Skip to content

Commit

Permalink
#189 Load attachments to a view separately from main timeline, so now…
Browse files Browse the repository at this point in the history
… we can load all attachments, not only the first one
  • Loading branch information
yvolk committed Oct 15, 2019
1 parent 60afab1 commit 59288fe
Show file tree
Hide file tree
Showing 16 changed files with 209 additions and 108 deletions.
Expand Up @@ -16,6 +16,7 @@

package org.andstatus.app.account;

import org.andstatus.app.context.MyContextHolder;
import org.andstatus.app.context.TestSuite;
import org.andstatus.app.origin.Origin;
import org.andstatus.app.util.StringUtils;
Expand Down Expand Up @@ -62,4 +63,14 @@ public void assertInputValues(Origin origin, String uniqueName) {
);
assertEquals(expected, accountName.getUniqueName());
}

@Test
public void testUniqueAccountName() {
AccountName accountName1 = AccountName.fromAccountName(MyContextHolder.get(), "someTester/Pump.io");
assertEquals(accountName1.toString(), accountName1.origin.getName(), "Pump.io");

AccountName accountName2 = AccountName.fromAccountName(MyContextHolder.get(), "someTester/PumpioTest");
assertEquals(accountName2.toString(), accountName2.origin.getName(), "PumpioTest");
}

}
Expand Up @@ -15,8 +15,6 @@
* limitations under the License.
*/

import android.net.Uri;

import org.andstatus.app.account.MyAccount;
import org.andstatus.app.context.TestSuite;
import org.andstatus.app.data.AttachedImageFile;
Expand All @@ -29,7 +27,6 @@
import org.andstatus.app.net.social.Actor;
import org.andstatus.app.net.social.Attachment;
import org.andstatus.app.net.social.ConnectionMock;
import org.andstatus.app.util.MyLog;
import org.junit.Before;
import org.junit.Test;

Expand Down Expand Up @@ -90,9 +87,7 @@ private DownloadData insertNote() throws IOException {
}

private void loadingTest(DownloadData dd) {
CachedImage image = new AttachedImageFile(dd.getDownloadId(), dd.getFilename(), dd.mediaMetadata,
dd.getStatus(), MyLog.uniqueCurrentTimeMS(), dd.getUri(), Uri.EMPTY, false)
.loadAndGetImage(CacheName.ATTACHED_IMAGE);
CachedImage image = new AttachedImageFile(dd).loadAndGetImage(CacheName.ATTACHED_IMAGE);
int width = image.getImageSize().x;
assertTrue("Not wide already " + width, width < 4000 && width > 10);
int height = image.getImageSize().y;
Expand Down
87 changes: 56 additions & 31 deletions app/src/main/java/org/andstatus/app/data/AttachedImageFile.java
Expand Up @@ -19,54 +19,56 @@
import android.database.Cursor;
import android.net.Uri;

import org.andstatus.app.context.MyContext;
import org.andstatus.app.database.table.DownloadTable;
import org.andstatus.app.graphics.CachedImage;
import org.andstatus.app.graphics.MediaMetadata;
import org.andstatus.app.service.CommandData;
import org.andstatus.app.service.MyServiceManager;
import org.andstatus.app.util.UriUtils;

import java.util.Collection;

import static org.andstatus.app.util.RelativeTime.DATETIME_MILLIS_NEVER;

public class AttachedImageFile extends ImageFile {
public static final AttachedImageFile EMPTY = new AttachedImageFile(0, "", MediaMetadata.EMPTY,
DownloadStatus.ABSENT, DATETIME_MILLIS_NEVER, Uri.EMPTY, Uri.EMPTY, false);
public static final AttachedImageFile EMPTY = new AttachedImageFile();
public final Uri uri;
private final long previewOfDownloadId;
private final Uri previewOfUri;
private final boolean previewOfIsVideo;

public static AttachedImageFile fromCursor(MyContext myContext, Cursor cursor) {
final long downloadId = DbUtils.getLong(cursor, DownloadTable.IMAGE_ID);
if (downloadId == 0) return EMPTY;

final long previewOfDownloadId = DbUtils.getLong(cursor, DownloadTable.PREVIEW_OF_DOWNLOAD_ID);
final Uri previewOfUri = previewOfDownloadId == 0
? Uri.EMPTY
: UriUtils.fromString(
MyQuery.idToStringColumnValue(myContext.getDatabase(), DownloadTable.TABLE_NAME, DownloadTable.URL,
previewOfDownloadId));
final boolean previewOfIsVideo = previewOfDownloadId != 0 && (MyContentType.load(
MyQuery.idToLongColumnValue(myContext.getDatabase(), DownloadTable.TABLE_NAME,
DownloadTable.CONTENT_TYPE, previewOfDownloadId)) == MyContentType.VIDEO);

return new AttachedImageFile(
downloadId,
DbUtils.getString(cursor, DownloadTable.IMAGE_FILE_NAME),
MediaMetadata.fromCursor(cursor),
private AttachedImageFile() {
super("", MediaMetadata.EMPTY, 0, DownloadStatus.ABSENT, DATETIME_MILLIS_NEVER);
this.uri = Uri.EMPTY;
this.previewOfDownloadId = 0;
this.previewOfUri = Uri.EMPTY;
this.previewOfIsVideo = false;
}

public static AttachedImageFile fromCursor(Cursor cursor) {
final long downloadId = DbUtils.getLong(cursor, DownloadTable._ID);
return downloadId == 0
? EMPTY
: new AttachedImageFile(downloadId, cursor);
}

private AttachedImageFile(long downloadId, Cursor cursor) {
super(DbUtils.getString(cursor, DownloadTable.FILE_NAME),
MediaMetadata.fromCursor(cursor), downloadId,
DownloadStatus.load(DbUtils.getLong(cursor, DownloadTable.DOWNLOAD_STATUS)),
DbUtils.getLong(cursor, DownloadTable.DOWNLOADED_DATE),
UriUtils.fromString(DbUtils.getString(cursor, DownloadTable.IMAGE_URI)),
previewOfUri, previewOfIsVideo);
DbUtils.getLong(cursor, DownloadTable.DOWNLOADED_DATE));
this.uri = UriUtils.fromString(DbUtils.getString(cursor, DownloadTable.URL));
this.previewOfDownloadId = DbUtils.getLong(cursor, DownloadTable.PREVIEW_OF_DOWNLOAD_ID);
this.previewOfUri = Uri.EMPTY;
this.previewOfIsVideo = false;
}

public AttachedImageFile(long downloadId, String filename, MediaMetadata mediaMetadata,
DownloadStatus downloadStatus, long downloadedDate, Uri uri,
Uri previewOfUri, boolean previewOfIsVideo) {
super(filename, mediaMetadata, downloadId, downloadStatus, downloadedDate);
this.uri = uri;
this.previewOfUri = previewOfUri;
this.previewOfIsVideo = previewOfIsVideo;
public AttachedImageFile(DownloadData data) {
super(data.getFilename(), data.mediaMetadata, data.getDownloadId(), data.getStatus(), data.getDownloadedDate());
this.uri = data.getUri();
this.previewOfDownloadId = 0;
this.previewOfUri = Uri.EMPTY;
this.previewOfIsVideo = false;
}

@Override
Expand All @@ -88,4 +90,27 @@ protected void requestDownload() {

MyServiceManager.sendCommand(CommandData.newFetchAttachment(0, downloadId));
}

AttachedImageFile resolvePreviews(Collection<AttachedImageFile> imageFiles) {
if (previewOfDownloadId != 0) {
for(AttachedImageFile other: imageFiles) {
if(previewOfDownloadId == other.downloadId) {
return new AttachedImageFile(this, other);
}
}
}
return this;
}

private AttachedImageFile(AttachedImageFile previewFile, AttachedImageFile other) {
super(previewFile.downloadFile.getFilename(),
previewFile.mediaMetadata,
previewFile.downloadId,
previewFile.downloadStatus,
previewFile.downloadedDate);
uri = previewFile.uri;
this.previewOfDownloadId = previewFile.previewOfDownloadId;
this.previewOfUri = other.uri;
this.previewOfIsVideo = other.contentType == MyContentType.VIDEO;
}
}
75 changes: 75 additions & 0 deletions app/src/main/java/org/andstatus/app/data/AttachedImageFiles.java
@@ -0,0 +1,75 @@
/*
* Copyright (C) 2019 yvolk (Yuri Volkov), http://yurivolkov.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.andstatus.app.data;

import org.andstatus.app.context.MyContext;
import org.andstatus.app.database.table.DownloadTable;
import org.andstatus.app.graphics.CacheName;
import org.andstatus.app.util.IsEmpty;

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

public class AttachedImageFiles implements IsEmpty {
public final static AttachedImageFiles EMPTY = new AttachedImageFiles(Collections.emptyList());

public final List<AttachedImageFile> list;

public AttachedImageFiles(List<AttachedImageFile> imageFiles) {
list = imageFiles;
}

public boolean isEmpty() {
return list.isEmpty();
}

public int size() {
return list.size();
}

public static AttachedImageFiles load(MyContext myContext, long noteId) {
final String sql = "SELECT *" +
" FROM " + DownloadTable.TABLE_NAME +
" WHERE " + DownloadTable.NOTE_ID + "=" + noteId +
" AND " + DownloadTable.DOWNLOAD_TYPE + "=" + DownloadType.ATTACHMENT.save() +
" AND " + DownloadTable.CONTENT_TYPE +
" IN(" + MyContentType.IMAGE.save() + ", " + MyContentType.VIDEO.save() + ")" +
" ORDER BY " + DownloadTable.DOWNLOAD_NUMBER;
List<AttachedImageFile> imageFiles1 = MyQuery.getList(myContext, sql, AttachedImageFile::fromCursor);
List<AttachedImageFile> imageFiles2 = imageFiles1.stream()
.filter(ImageFile::nonEmpty)
.map(imageFile -> imageFile.resolvePreviews(imageFiles1))
.collect(Collectors.toList());
return new AttachedImageFiles(imageFiles2);
}

@Override
public String toString() {
return this.getClass().getSimpleName() + "{" +
list +
'}';
}

public void preloadImagesAsync() {
for (AttachedImageFile imageFile: list) {
if (imageFile.contentType == MyContentType.IMAGE) {
imageFile.preloadImageAsync(CacheName.ATTACHED_IMAGE);
}
}
}
}
Expand Up @@ -136,19 +136,21 @@ private void addWithMultipleAttachments(AActivity activity) {
final Attachments attachments = activity.getNote().attachments;
attachments.add(
Attachment.fromUriAndMimeType("https://gnusocial.example.com/api/statuses/update.json",
"text/html; charset=utf-8"));
"application/json; charset=utf-8"));
attachments.add(
Attachment.fromUriAndMimeType("https://www.w3.org/Protocols/rfc1341/7_2_Multipart.html",
"text/html; charset=iso-8859-1"));
attachments.add(
Attachment.fromUriAndMimeType("https://www.w3.org/2008/site/images/logo-w3c-mobile-lg",
"image"));
addActivity(activity);
assertEquals(attachments.toString(), 3, attachments.size());

final Attachment attachment0 = attachments.list.get(0);
final Attachment attachment2 = attachments.list.get(2);
assertEquals("Image should be the first " + attachments, 0,
attachment2.getDownloadNumber());
assertEquals("Download number should change " + attachments, 1,
assertEquals("Download number should change " + attachments, 2,
attachment0.getDownloadNumber());
assertEquals("Image attachment should be number 2 " + attachments, "image",
attachment2.mimeType);
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/org/andstatus/app/data/ImageFile.java
Expand Up @@ -40,8 +40,8 @@
import io.vavr.control.Try;

public abstract class ImageFile implements IsEmpty, IdentifiableInstance {
private final DownloadFile downloadFile;
private volatile MediaMetadata mediaMetadata;
final DownloadFile downloadFile;
volatile MediaMetadata mediaMetadata;
protected volatile MyContentType contentType;
public final long downloadId;
public final DownloadStatus downloadStatus;
Expand Down
5 changes: 4 additions & 1 deletion app/src/main/java/org/andstatus/app/data/MyContentType.java
Expand Up @@ -31,7 +31,8 @@ public enum MyContentType {
IMAGE("image/*", 2, 1),
TEXT("text/*", 3, 3),
VIDEO("video/*", 4, 2),
UNKNOWN("*/*", 0, 4);
APPLICATION("application/*", 5, 4),
UNKNOWN("*/*", 0, 5);

private static final String TAG = MyContentType.class.getSimpleName();

Expand All @@ -58,6 +59,8 @@ public static MyContentType fromUri(DownloadType downloadType, ContentResolver c
return VIDEO;
} else if (mimeType.startsWith("text")) {
return TEXT;
} else if (mimeType.startsWith("application")) {
return APPLICATION;
} else {
return UNKNOWN;
}
Expand Down
12 changes: 12 additions & 0 deletions app/src/main/java/org/andstatus/app/data/MyQuery.java
Expand Up @@ -715,6 +715,18 @@ public static <T> Set<T> get(@NonNull MyContext myContext, @NonNull String sql,
);
}

/**
* @return Empty list on UI thread
*/
@NonNull
public static <T> List<T> getList(@NonNull MyContext myContext, @NonNull String sql, Function<Cursor, T> fromCursor) {
return foldLeft(myContext,
sql,
new ArrayList<>(),
t -> cursor -> { t.add(fromCursor.apply(cursor)); return t; }
);
}

/**
* @return identity on UI thread
*/
Expand Down
Expand Up @@ -85,6 +85,7 @@ public class ProjectionMap {
TIMELINE.put(NoteTable.UPDATED_DATE, NoteTable.UPDATED_DATE);
TIMELINE.put(NoteTable.NOTE_STATUS, NoteTable.NOTE_STATUS);
TIMELINE.put(NoteTable.INS_DATE, NoteTable.INS_DATE);
TIMELINE.put(NoteTable.ATTACHMENTS_COUNT, NoteTable.ATTACHMENTS_COUNT);
}

private ProjectionMap() {
Expand Down
37 changes: 1 addition & 36 deletions app/src/main/java/org/andstatus/app/data/TimelineSql.java
Expand Up @@ -26,7 +26,6 @@
import org.andstatus.app.context.MyPreferences;
import org.andstatus.app.database.table.ActivityTable;
import org.andstatus.app.database.table.ActorTable;
import org.andstatus.app.database.table.DownloadTable;
import org.andstatus.app.database.table.GroupMembersTable;
import org.andstatus.app.database.table.NoteTable;
import org.andstatus.app.timeline.meta.Timeline;
Expand Down Expand Up @@ -125,33 +124,6 @@ private static String tablesForTimeline(Uri uri, String[] projection, int subQue
+ " ON (" + NOTE_TABLE_ALIAS + "." + BaseColumns._ID + "="
+ ProjectionMap.ACTIVITY_TABLE_ALIAS + "." + ActivityTable.NOTE_ID
+ noteWhere.getAndWhere() + ")";
if (columns.contains(DownloadTable.IMAGE_FILE_NAME)) {
tables = "(" + tables + ") LEFT OUTER JOIN ("
+ "SELECT "
+ DownloadTable._ID + ", "
+ DownloadTable.NOTE_ID + ", "
+ DownloadTable.DOWNLOAD_TYPE + ", "
+ DownloadTable.CONTENT_TYPE + ", "
+ DownloadTable.DOWNLOAD_NUMBER + ", "
+ DownloadTable.PREVIEW_OF_DOWNLOAD_ID + ", "
+ DownloadTable.DOWNLOAD_STATUS + ", "
+ DownloadTable.WIDTH + ", "
+ DownloadTable.HEIGHT + ", "
+ DownloadTable.DURATION + ", "
+ DownloadTable.URL + ", "
+ DownloadTable.FILE_NAME
+ " FROM " + DownloadTable.TABLE_NAME
+ ") AS " + ProjectionMap.ATTACHMENT_IMAGE_TABLE_ALIAS
+ " ON "
+ ProjectionMap.ATTACHMENT_IMAGE_TABLE_ALIAS + "." + DownloadTable.NOTE_ID
+ "=" + ProjectionMap.ACTIVITY_TABLE_ALIAS + "." + ActivityTable.NOTE_ID + " AND "
+ ProjectionMap.ATTACHMENT_IMAGE_TABLE_ALIAS + "." + DownloadTable.DOWNLOAD_TYPE
+ "=" + DownloadType.ATTACHMENT.save() + " AND "
+ ProjectionMap.ATTACHMENT_IMAGE_TABLE_ALIAS + "." + DownloadTable.CONTENT_TYPE
+ " IN(" + MyContentType.IMAGE.save() + ", " + MyContentType.VIDEO.save() + ") AND "
+ ProjectionMap.ATTACHMENT_IMAGE_TABLE_ALIAS + "." + DownloadTable.DOWNLOAD_NUMBER
+ "=0";
}
return tables;
}

Expand Down Expand Up @@ -211,14 +183,7 @@ public static Set<String> getTimelineProjection() {
columnNames.add(NoteTable.VIA);
columnNames.add(NoteTable.REBLOGGED);
if (MyPreferences.getDownloadAndDisplayAttachedImages()) {
columnNames.add(DownloadTable.IMAGE_ID);
columnNames.add(DownloadTable.IMAGE_URI);
columnNames.add(DownloadTable.IMAGE_FILE_NAME);
columnNames.add(DownloadTable.PREVIEW_OF_DOWNLOAD_ID);
columnNames.add(DownloadTable.DOWNLOAD_STATUS);
columnNames.add(DownloadTable.WIDTH);
columnNames.add(DownloadTable.HEIGHT);
columnNames.add(DownloadTable.DURATION);
columnNames.add(NoteTable.ATTACHMENTS_COUNT);
}
if (SharedPreferencesUtil.getBoolean(MyPreferences.KEY_MARK_REPLIES_TO_ME_IN_TIMELINE, true)
|| SharedPreferencesUtil.getBoolean(
Expand Down

0 comments on commit 59288fe

Please sign in to comment.