added status edit media support, bug fix

This commit is contained in:
nuclearfog 2023-04-21 16:45:42 +02:00
parent 0baaed7579
commit 7aa702604a
No known key found for this signature in database
GPG Key ID: 03488A185C476379
14 changed files with 216 additions and 130 deletions

View File

@ -420,7 +420,7 @@ public interface Connection {
* @param mediaIds IDs of the uploaded media files if any * @param mediaIds IDs of the uploaded media files if any
* @return uploaded status * @return uploaded status
*/ */
Status uploadStatus(StatusUpdate update, long[] mediaIds) throws ConnectionException; Status uploadStatus(StatusUpdate update, List<Long> mediaIds) throws ConnectionException;
/** /**
* create userlist * create userlist

View File

@ -598,7 +598,7 @@ public class Mastodon implements Connection {
@Override @Override
public Status uploadStatus(StatusUpdate update, long[] mediaIds) throws MastodonException { public Status uploadStatus(StatusUpdate update, List<Long> mediaIds) throws MastodonException {
List<String> params = new ArrayList<>(); List<String> params = new ArrayList<>();
// add identifier to prevent duplicate posts // add identifier to prevent duplicate posts
params.add("Idempotency-Key=" + System.currentTimeMillis() / 5000); params.add("Idempotency-Key=" + System.currentTimeMillis() / 5000);
@ -619,8 +619,13 @@ public class Mastodon implements Connection {
params.add("visibility=unlisted"); params.add("visibility=unlisted");
else else
params.add("visibility=public"); params.add("visibility=public");
for (long mediaId : mediaIds) for (long mediaId : mediaIds) {
params.add("media_ids[]=" + mediaId); params.add("media_ids[]=" + mediaId);
}
// add media keys of a previous status
for (String mediaKey : update.getMediaKeys()) {
params.add("media_ids[]=" + mediaKey);
}
if (update.getPoll() != null) { if (update.getPoll() != null) {
PollUpdate poll = update.getPoll(); PollUpdate poll = update.getPoll();
for (String option : poll.getOptions()) for (String option : poll.getOptions())

View File

@ -722,7 +722,7 @@ public class TwitterV1 implements Connection {
@Override @Override
public Status uploadStatus(StatusUpdate update, long[] mediaIds) throws TwitterException { public Status uploadStatus(StatusUpdate update, List<Long> mediaIds) throws TwitterException {
List<String> params = new ArrayList<>(); List<String> params = new ArrayList<>();
if (update.getText() != null) if (update.getText() != null)
params.add("status=" + StringUtils.encode(update.getText())); params.add("status=" + StringUtils.encode(update.getText()));
@ -730,7 +730,7 @@ public class TwitterV1 implements Connection {
params.add("in_reply_to_status_id=" + update.getReplyId()); params.add("in_reply_to_status_id=" + update.getReplyId());
if (update.isSensitive()) if (update.isSensitive())
params.add("possibly_sensitive=true"); params.add("possibly_sensitive=true");
if (mediaIds != null && mediaIds.length > 0) { if (!mediaIds.isEmpty()) {
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
for (long id : mediaIds) for (long id : mediaIds)
buf.append(id).append("%2C"); buf.append(id).append("%2C");

View File

@ -13,6 +13,9 @@ import org.nuclearfog.twidda.backend.helper.StatusUpdate;
import org.nuclearfog.twidda.model.Status; import org.nuclearfog.twidda.model.Status;
import org.nuclearfog.twidda.ui.activities.StatusEditor; import org.nuclearfog.twidda.ui.activities.StatusEditor;
import java.util.LinkedList;
import java.util.List;
/** /**
* Background task for posting a status * Background task for posting a status
* *
@ -35,11 +38,12 @@ public class StatusUpdater extends AsyncExecutor<StatusUpdate, StatusUpdater.Sta
protected StatusUpdateResult doInBackground(@NonNull StatusUpdate update) { protected StatusUpdateResult doInBackground(@NonNull StatusUpdate update) {
try { try {
// upload media first // upload media first
MediaStatus[] mediaUpdates = update.getMediaUpdates(); List<Long> mediaIds = new LinkedList<>();
long[] mediaIds = new long[mediaUpdates.length]; for (MediaStatus mediaStatus : update.getMediaStatuses()) {
for (int pos = 0; pos < mediaUpdates.length; pos++) { if (mediaStatus.isLocal()) {
// upload media file and save media ID long mediaId = connection.uploadMedia(mediaStatus);
mediaIds[pos] = connection.uploadMedia(mediaUpdates[pos]); mediaIds.add(mediaId);
}
} }
// upload status // upload status
Status status = connection.uploadStatus(update, mediaIds); Status status = connection.uploadStatus(update, mediaIds);

View File

@ -1,5 +1,8 @@
package org.nuclearfog.twidda.backend.helper; package org.nuclearfog.twidda.backend.helper;
import android.content.ContentResolver;
import android.net.Uri;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import java.io.IOException; import java.io.IOException;
@ -18,13 +21,52 @@ public class MediaStatus implements Serializable {
private InputStream inputStream; private InputStream inputStream;
private String mimeType; private String mimeType;
private String path;
private boolean local;
/** /**
* @param inputStream stream of the media (local or online) * create MediaStatus from an online source
* @param mimeType MIME type e.g. image/jpeg *
* @param inputStream inputstream to fetch data from internet
* @param mimeType MIME type of the media
*/ */
public MediaStatus(InputStream inputStream, String mimeType) { public MediaStatus(InputStream inputStream, String mimeType) {
this.inputStream = inputStream; this.inputStream = inputStream;
this.mimeType = mimeType; this.mimeType = mimeType;
local = false;
}
/**
* create MediaStatus from an offline source
*
* @param path path to the local file
* @param mimeType MIME type of the file
*/
public MediaStatus(String path, String mimeType) {
this.path = path;
this.mimeType = mimeType;
local = true;
}
/**
* create a stream to upload media file
*
* @param resolver content resolver used to create stream and determine MIME type of the file
* @return true if stream is prepared, false if an error occured
*/
public boolean openStream(ContentResolver resolver) {
if (path == null)
return false;
Uri uri = Uri.parse(path);
try {
inputStream = resolver.openInputStream(uri);
mimeType = resolver.getType(uri);
// check if stream is valid
return inputStream != null && mimeType != null && inputStream.available() > 0;
} catch (IOException e) {
e.printStackTrace();
}
return false;
} }
/** /**
@ -52,6 +94,10 @@ public class MediaStatus implements Serializable {
} }
} }
public boolean isLocal() {
return local;
}
/** /**
* close stream * close stream
*/ */

View File

@ -10,8 +10,6 @@ import androidx.documentfile.provider.DocumentFile;
import org.nuclearfog.twidda.model.Instance; import org.nuclearfog.twidda.model.Instance;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable; import java.io.Serializable;
import java.util.Arrays; import java.util.Arrays;
import java.util.Set; import java.util.Set;
@ -26,7 +24,7 @@ public class MessageUpdate implements Serializable {
private static final long serialVersionUID = 991295406939128220L; private static final long serialVersionUID = 991295406939128220L;
private String uriString; private String mediaUri;
private MediaStatus mediaUpdate; private MediaStatus mediaUpdate;
private String name = ""; private String name = "";
private String text = ""; private String text = "";
@ -84,7 +82,7 @@ public class MessageUpdate implements Serializable {
*/ */
@Nullable @Nullable
public Uri getMediaUri() { public Uri getMediaUri() {
return Uri.parse(uriString); return Uri.parse(mediaUri);
} }
/** /**
@ -98,14 +96,11 @@ public class MessageUpdate implements Serializable {
DocumentFile file = DocumentFile.fromSingleUri(context, uri); DocumentFile file = DocumentFile.fromSingleUri(context, uri);
String mime = context.getContentResolver().getType(uri); String mime = context.getContentResolver().getType(uri);
// check if file is valid // check if file is valid
if (file == null || file.length() == 0) { if (mime == null || file == null || file.length() == 0 || !supportedFormats.contains(mime)) {
return false; return false;
} }
// check if file format is supported this.mediaUri = uri.toString();
if (mime == null || !supportedFormats.contains(mime)) { mediaUpdate = new MediaStatus(uri.toString(), mime);
return false;
}
this.uriString = uri.toString();
return true; return true;
} }
@ -115,22 +110,7 @@ public class MessageUpdate implements Serializable {
* @return true if initialization succeded * @return true if initialization succeded
*/ */
public boolean prepare(ContentResolver resolver) { public boolean prepare(ContentResolver resolver) {
if (uriString == null) { return mediaUpdate == null || mediaUpdate.openStream(resolver);
// no need to check media files if not attached
return true;
}
try {
Uri uri = Uri.parse(uriString);
String mimeType = resolver.getType(uri);
InputStream fileStream = resolver.openInputStream(uri);
if (fileStream != null && mimeType != null && fileStream.available() > 0) {
mediaUpdate = new MediaStatus(fileStream, mimeType);
return true;
}
} catch (IOException e) {
e.printStackTrace();
}
return false;
} }
/** /**
@ -163,6 +143,6 @@ public class MessageUpdate implements Serializable {
@NonNull @NonNull
@Override @Override
public String toString() { public String toString() {
return "to=\"" + name + "\" text=\"" + text + "\" media=" + (mediaUpdate != null); return "to=\"" + name + "\" text=\"" + text + "\" media=" + mediaUpdate;
} }
} }

View File

@ -10,9 +10,9 @@ import androidx.annotation.Nullable;
import androidx.documentfile.provider.DocumentFile; import androidx.documentfile.provider.DocumentFile;
import org.nuclearfog.twidda.model.Instance; import org.nuclearfog.twidda.model.Instance;
import org.nuclearfog.twidda.model.Media;
import org.nuclearfog.twidda.model.Status; import org.nuclearfog.twidda.model.Status;
import java.io.InputStream;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -76,18 +76,20 @@ public class StatusUpdate implements Serializable {
private PollUpdate poll; private PollUpdate poll;
@Nullable @Nullable
private LocationUpdate location; private LocationUpdate location;
private MediaStatus[] mediaUpdates = {};
private int attachment = EMPTY; private int attachment = EMPTY;
// helper attributes // helper attributes
@Nullable @Nullable
private Instance instance; private Instance instance;
private List<String> mediaUriStrings = new ArrayList<>(5); private List<String> previews = new ArrayList<>();
private List<String> mediaKeys = new ArrayList<>();
private List<MediaStatus> mediaStatuses = new ArrayList<>();
private Set<String> supportedFormats = new TreeSet<>(); private Set<String> supportedFormats = new TreeSet<>();
private boolean attachmentLimitReached = false; private boolean attachmentLimitReached = false;
/** /**
* set existing status to edit * set informations of an existing status to edit these
* *
* @param status existing status * @param status existing status
*/ */
@ -106,6 +108,36 @@ public class StatusUpdate implements Serializable {
} }
} }
/**
* set information media files attached to an existing status
*
* @param status status contianing media
* @return attached media type {@link #EMPTY,#MEDIA_VIDEO,#MEDIA_IMAGE,#MEDIA_GIF}
*/
public int setMedia(Status status) {
if (status.getMedia().length > 0) {
for (Media media : status.getMedia()) {
mediaKeys.add(media.getKey());
previews.add(media.getUrl());
}
attachmentLimitReached = true;
switch (status.getMedia()[0].getMediaType()) {
case Media.GIF:
attachment = MEDIA_GIF;
break;
case Media.PHOTO:
attachment = MEDIA_IMAGE;
break;
case Media.VIDEO:
attachment = MEDIA_VIDEO;
break;
}
}
return attachment;
}
/** /**
* set ID of the replied status * set ID of the replied status
* *
@ -117,6 +149,8 @@ public class StatusUpdate implements Serializable {
/** /**
* add status text * add status text
*
* @param text status text
*/ */
public void addText(String text) { public void addText(String text) {
this.text = text; this.text = text;
@ -142,8 +176,9 @@ public class StatusUpdate implements Serializable {
case MEDIA_GIF: case MEDIA_GIF:
DocumentFile file = DocumentFile.fromSingleUri(context, mediaUri); DocumentFile file = DocumentFile.fromSingleUri(context, mediaUri);
if (file != null && file.length() > 0) { if (file != null && file.length() > 0) {
mediaUriStrings.add(mediaUri.toString()); previews.add(mediaUri.toString());
if (mediaUriStrings.size() == instance.getGifLimit()) { mediaStatuses.add(new MediaStatus(mediaUri.toString(), mime));
if (mediaStatuses.size() == instance.getGifLimit()) {
attachmentLimitReached = true; attachmentLimitReached = true;
} }
return MEDIA_GIF; return MEDIA_GIF;
@ -161,8 +196,9 @@ public class StatusUpdate implements Serializable {
case MEDIA_IMAGE: case MEDIA_IMAGE:
DocumentFile file = DocumentFile.fromSingleUri(context, mediaUri); DocumentFile file = DocumentFile.fromSingleUri(context, mediaUri);
if (file != null && file.length() > 0) { if (file != null && file.length() > 0) {
mediaUriStrings.add(mediaUri.toString()); previews.add(mediaUri.toString());
if (mediaUriStrings.size() == instance.getImageLimit()) { mediaStatuses.add(new MediaStatus(mediaUri.toString(), mime));
if (mediaStatuses.size() == instance.getImageLimit()) {
attachmentLimitReached = true; attachmentLimitReached = true;
} }
return MEDIA_IMAGE; return MEDIA_IMAGE;
@ -179,8 +215,9 @@ public class StatusUpdate implements Serializable {
case MEDIA_VIDEO: case MEDIA_VIDEO:
DocumentFile file = DocumentFile.fromSingleUri(context, mediaUri); DocumentFile file = DocumentFile.fromSingleUri(context, mediaUri);
if (file != null && file.length() > 0) { if (file != null && file.length() > 0) {
mediaUriStrings.add(mediaUri.toString()); previews.add(mediaUri.toString());
if (mediaUriStrings.size() == instance.getVideoLimit()) { mediaStatuses.add(new MediaStatus(mediaUri.toString(), mime));
if (mediaStatuses.size() == instance.getVideoLimit()) {
attachmentLimitReached = true; attachmentLimitReached = true;
} }
return MEDIA_VIDEO; return MEDIA_VIDEO;
@ -299,8 +336,8 @@ public class StatusUpdate implements Serializable {
* *
* @return list of media updates * @return list of media updates
*/ */
public MediaStatus[] getMediaUpdates() { public List<MediaStatus> getMediaStatuses() {
return mediaUpdates; return new ArrayList<>(mediaStatuses);
} }
/** /**
@ -309,9 +346,9 @@ public class StatusUpdate implements Serializable {
* @return media uri array * @return media uri array
*/ */
public Uri[] getMediaUris() { public Uri[] getMediaUris() {
Uri[] result = new Uri[mediaUriStrings.size()]; Uri[] result = new Uri[previews.size()];
for (int i = 0 ; i < result.length ; i++) { for (int i = 0 ; i < result.length ; i++) {
result[i] = Uri.parse(mediaUriStrings.get(i)); result[i] = Uri.parse(previews.get(i));
} }
return result; return result;
} }
@ -336,6 +373,15 @@ public class StatusUpdate implements Serializable {
return location; return location;
} }
/**
* get media keys (IDs) of online media
*
* @return media key
*/
public String[] getMediaKeys() {
return mediaKeys.toArray(new String[0]);
}
/** /**
* @return true if status content is sensitive * @return true if status content is sensitive
*/ */
@ -382,7 +428,7 @@ public class StatusUpdate implements Serializable {
* @return true if media is attached * @return true if media is attached
*/ */
public boolean isEmpty() { public boolean isEmpty() {
return mediaUriStrings.isEmpty() && location == null && poll == null && getText() == null; return previews.isEmpty() && location == null && poll == null && getText() == null;
} }
/** /**
@ -391,21 +437,16 @@ public class StatusUpdate implements Serializable {
* @return true if success, false if an error occurs * @return true if success, false if an error occurs
*/ */
public boolean prepare(ContentResolver resolver) { public boolean prepare(ContentResolver resolver) {
if (mediaUriStrings.isEmpty()) if (previews.isEmpty())
return true; return true;
try { try {
// open input streams // open input streams
mediaUpdates = new MediaStatus[mediaUriStrings.size()]; for (MediaStatus mediaStatus : mediaStatuses) {
for (int i = 0; i < mediaUpdates.length; i++) { boolean success = mediaStatus.openStream(resolver);
Uri uri = Uri.parse(mediaUriStrings.get(i)); if (!success) {
InputStream is = resolver.openInputStream(uri);
String mime = resolver.getType(uri);
// check if stream is valid
if (is != null && mime != null && is.available() > 0) {
mediaUpdates[i] = new MediaStatus(is, mime);
} else {
return false; return false;
} }
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@ -418,8 +459,10 @@ public class StatusUpdate implements Serializable {
* close all open streams * close all open streams
*/ */
public void close() { public void close() {
for (MediaStatus mediaUpdate : mediaUpdates) { for (MediaStatus mediaUpdate : mediaStatuses) {
mediaUpdate.close(); if (mediaUpdate != null) {
mediaUpdate.close();
}
} }
} }

View File

@ -1,8 +1,9 @@
package org.nuclearfog.twidda.backend.helper; package org.nuclearfog.twidda.backend.helper;
import androidx.annotation.Nullable;
import org.nuclearfog.twidda.model.Status; import org.nuclearfog.twidda.model.Status;
import java.util.Arrays;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
@ -30,6 +31,17 @@ public class Statuses extends LinkedList<Status> {
super(); super();
} }
/**
* create a copy of statuses
*
* @param statuses list to copy
*/
public Statuses(Statuses statuses) {
super(statuses);
this.minId = statuses.getMinId();
this.maxId = statuses.getMaxId();
}
/** /**
* @param minId minimum ID of the first item * @param minId minimum ID of the first item
* @param maxId maximum ID of the last item * @param maxId maximum ID of the last item
@ -40,6 +52,15 @@ public class Statuses extends LinkedList<Status> {
this.maxId = maxId; this.maxId = maxId;
} }
/**
* @inheritDoc
*/
@Nullable
@Override
public Status get(int index) {
return super.get(index);
}
/** /**
* get the minimum ID of this list. If not set, use the first item's ID * get the minimum ID of this list. If not set, use the first item's ID
* *
@ -114,16 +135,4 @@ public class Statuses extends LinkedList<Status> {
minId = statuses.getMinId(); minId = statuses.getMinId();
maxId = statuses.getMaxId(); maxId = statuses.getMaxId();
} }
/**
* replace all items with new ones
*
* @param statuses new items to insert
*/
public void replaceAll(Status[] statuses) {
clear();
addAll(Arrays.asList(statuses));
minId = statuses[0].getId();
maxId = statuses[statuses.length - 1].getId();
}
} }

View File

@ -143,6 +143,9 @@ public class StatusEditor extends MediaActivity implements OnClickListener, OnPr
preferenceDialog = new StatusPreferenceDialog(this, statusUpdate); preferenceDialog = new StatusPreferenceDialog(this, statusUpdate);
pollDialog = new PollDialog(this, this); pollDialog = new PollDialog(this, this);
emojiPicker = new EmojiPicker(this, this); emojiPicker = new EmojiPicker(this, this);
adapter = new IconAdapter(settings, true);
iconList.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, true));
iconList.setAdapter(adapter);
AppStyles.setEditorTheme(root, background); AppStyles.setEditorTheme(root, background);
if (!settings.getLogin().getConfiguration().locationSupported()) { if (!settings.getLogin().getConfiguration().locationSupported()) {
@ -166,6 +169,10 @@ public class StatusEditor extends MediaActivity implements OnClickListener, OnPr
if (editStatus) { if (editStatus) {
statusUpdate.setStatus(status); statusUpdate.setStatus(status);
statusText.append(status.getText()); statusText.append(status.getText());
if (status.getMedia().length > 0) {
int mediaType = statusUpdate.setMedia(status);
addMedia(mediaType);
}
} else { } else {
statusUpdate.addReplyStatusId(status.getId()); statusUpdate.addReplyStatusId(status.getId());
statusUpdate.setVisibility(status.getVisibility()); statusUpdate.setVisibility(status.getVisibility());
@ -177,11 +184,8 @@ public class StatusEditor extends MediaActivity implements OnClickListener, OnPr
statusText.append(prefix); statusText.append(prefix);
} }
} }
adapter = new IconAdapter(settings, true);
adapter.addOnMediaClickListener(this);
iconList.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, true));
iconList.setAdapter(adapter);
adapter.addOnMediaClickListener(this);
statusText.addTextChangedListener(this); statusText.addTextChangedListener(this);
emojiButton.setOnClickListener(this); emojiButton.setOnClickListener(this);
preference.setOnClickListener(this); preference.setOnClickListener(this);
@ -332,31 +336,7 @@ public class StatusEditor extends MediaActivity implements OnClickListener, OnPr
@Override @Override
protected void onMediaFetched(int resultType, @NonNull Uri uri) { protected void onMediaFetched(int resultType, @NonNull Uri uri) {
int mediaType = statusUpdate.addMedia(this, uri); int mediaType = statusUpdate.addMedia(this, uri);
switch (mediaType) { addMedia(mediaType);
case StatusUpdate.MEDIA_IMAGE:
adapter.addImageItem();
break;
case StatusUpdate.MEDIA_GIF:
adapter.addGifItem();
break;
case StatusUpdate.MEDIA_VIDEO:
adapter.addVideoItem();
break;
case StatusUpdate.MEDIA_ERROR:
Toast.makeText(getApplicationContext(), R.string.error_adding_media, Toast.LENGTH_SHORT).show();
break;
}
// hide media button if limit is reached
if (statusUpdate.mediaLimitReached()) {
mediaBtn.setVisibility(View.GONE);
}
// hide poll button
if (mediaType != StatusUpdate.MEDIA_ERROR && pollBtn.getVisibility() != View.GONE) {
pollBtn.setVisibility(View.GONE);
}
} }
@ -423,6 +403,34 @@ public class StatusEditor extends MediaActivity implements OnClickListener, OnPr
} }
} }
private void addMedia(int mediaType) {
switch (mediaType) {
case StatusUpdate.MEDIA_IMAGE:
adapter.addImageItem();
break;
case StatusUpdate.MEDIA_GIF:
adapter.addGifItem();
break;
case StatusUpdate.MEDIA_VIDEO:
adapter.addVideoItem();
break;
case StatusUpdate.MEDIA_ERROR:
Toast.makeText(getApplicationContext(), R.string.error_adding_media, Toast.LENGTH_SHORT).show();
break;
}
// hide media button if limit is reached
if (statusUpdate.mediaLimitReached()) {
mediaBtn.setVisibility(View.GONE);
}
// hide poll button
if (mediaType != StatusUpdate.MEDIA_ERROR && pollBtn.getVisibility() != View.GONE) {
pollBtn.setVisibility(View.GONE);
}
}
/** /**
* called when the status was successfully updated * called when the status was successfully updated
*/ */

View File

@ -189,7 +189,7 @@ public class MessageAdapter extends Adapter<ViewHolder> implements OnItemClickLi
public void replaceItems(Messages newMessages) { public void replaceItems(Messages newMessages) {
messages.clear(); messages.clear();
messages.replaceAll(newMessages); messages.replaceAll(newMessages);
if (newMessages.getNextCursor() != null && !newMessages.getNextCursor().isEmpty()) { if (newMessages.getNextCursor() != null && !newMessages.getNextCursor().isEmpty() && messages.peekLast() != null) {
// add placeholder // add placeholder
messages.add(null); messages.add(null);
} }

View File

@ -150,8 +150,8 @@ public class StatusAdapter extends Adapter<ViewHolder> implements OnHolderClickL
* *
* @return item array * @return item array
*/ */
public Status[] getItems() { public Statuses getItems() {
return items.toArray(new Status[0]); return new Statuses(items);
} }
/** /**
@ -186,20 +186,7 @@ public class StatusAdapter extends Adapter<ViewHolder> implements OnHolderClickL
*/ */
public void replaceItems(@NonNull Statuses newItems) { public void replaceItems(@NonNull Statuses newItems) {
items.replaceAll(newItems); items.replaceAll(newItems);
if (items.size() > MIN_COUNT && items.getMaxId() != Statuses.NO_ID) if (items.size() > MIN_COUNT && items.getMaxId() != Statuses.NO_ID && items.peekLast() != null)
items.add(null);
loadingIndex = NO_LOADING;
notifyDataSetChanged();
}
/**
* Replace all items in the list
*
* @param newItems array of statuses to add
*/
public void replaceItems(Status[] newItems) {
items.replaceAll(newItems);
if (items.size() > MIN_COUNT)
items.add(null); items.add(null);
loadingIndex = NO_LOADING; loadingIndex = NO_LOADING;
notifyDataSetChanged(); notifyDataSetChanged();
@ -252,7 +239,10 @@ public class StatusAdapter extends Adapter<ViewHolder> implements OnHolderClickL
*/ */
public long getTopItemId() { public long getTopItemId() {
if (!items.isEmpty() && items.get(0) != null) { if (!items.isEmpty() && items.get(0) != null) {
return items.get(0).getId(); Status status = items.get(0);
if (status != null) {
return status.getId();
}
} }
return 0L; return 0L;
} }

View File

@ -175,7 +175,7 @@ public class UserAdapter extends Adapter<ViewHolder> implements OnHolderClickLis
*/ */
public void replaceItems(Users newUsers) { public void replaceItems(Users newUsers) {
users.replaceAll(newUsers); users.replaceAll(newUsers);
if (users.getNext() != 0L) { if (users.getNext() != 0L && users.peekLast() != null) {
users.add(null); users.add(null);
} }
notifyDataSetChanged(); notifyDataSetChanged();

View File

@ -177,7 +177,7 @@ public class UserlistAdapter extends Adapter<ViewHolder> implements OnHolderClic
*/ */
public void replaceItems(UserLists newUserlists) { public void replaceItems(UserLists newUserlists) {
userlists.replaceAll(newUserlists); userlists.replaceAll(newUserlists);
if (userlists.getNext() != 0L) { if (userlists.getNext() != 0L && userlists.peekLast() != null) {
// Add placeholder // Add placeholder
userlists.add(null); userlists.add(null);
} }

View File

@ -18,6 +18,7 @@ import org.nuclearfog.twidda.backend.async.AsyncExecutor.AsyncCallback;
import org.nuclearfog.twidda.backend.async.StatusLoader; import org.nuclearfog.twidda.backend.async.StatusLoader;
import org.nuclearfog.twidda.backend.async.StatusLoader.StatusParameter; import org.nuclearfog.twidda.backend.async.StatusLoader.StatusParameter;
import org.nuclearfog.twidda.backend.async.StatusLoader.StatusResult; import org.nuclearfog.twidda.backend.async.StatusLoader.StatusResult;
import org.nuclearfog.twidda.backend.helper.Statuses;
import org.nuclearfog.twidda.backend.utils.ErrorHandler; import org.nuclearfog.twidda.backend.utils.ErrorHandler;
import org.nuclearfog.twidda.model.Status; import org.nuclearfog.twidda.model.Status;
import org.nuclearfog.twidda.ui.activities.StatusActivity; import org.nuclearfog.twidda.ui.activities.StatusActivity;
@ -142,8 +143,8 @@ public class StatusFragment extends ListFragment implements StatusSelectListener
} }
if (savedInstanceState != null) { if (savedInstanceState != null) {
Serializable data = savedInstanceState.getSerializable(KEY_STATUS_FRAGMENT_SAVE); Serializable data = savedInstanceState.getSerializable(KEY_STATUS_FRAGMENT_SAVE);
if (data instanceof Status[]) { if (data instanceof Statuses) {
adapter.replaceItems((Status[]) data); adapter.replaceItems((Statuses) data);
} }
} }
setAdapter(adapter); setAdapter(adapter);