added status edit support

This commit is contained in:
nuclearfog 2023-04-19 17:05:52 +02:00
parent 05102cbc9c
commit 9f2ab52964
No known key found for this signature in database
GPG Key ID: 03488A185C476379
10 changed files with 174 additions and 60 deletions

View File

@ -417,8 +417,9 @@ public interface Connection {
*
* @param update status update information
* @param mediaIds IDs of the uploaded media files if any
* @return uploaded status
*/
void uploadStatus(StatusUpdate update, long[] mediaIds) throws ConnectionException;
Status uploadStatus(StatusUpdate update, long[] mediaIds) throws ConnectionException;
/**
* create userlist

View File

@ -593,7 +593,7 @@ public class Mastodon implements Connection {
@Override
public void uploadStatus(StatusUpdate update, long[] mediaIds) throws MastodonException {
public Status uploadStatus(StatusUpdate update, long[] mediaIds) throws MastodonException {
List<String> params = new ArrayList<>();
// add identifier to prevent duplicate posts
params.add("Idempotency-Key=" + System.currentTimeMillis() / 5000);
@ -625,10 +625,15 @@ public class Mastodon implements Connection {
params.add("poll[hide_totals]=" + poll.hideTotalVotes());
}
try {
Response response = post(ENDPOINT_STATUS, params);
if (response.code() != 200) {
throw new MastodonException(response);
Response response;
if (update.statusExists())
response = put(ENDPOINT_STATUS + update.getStatusId(), params);
else
response = post(ENDPOINT_STATUS, params);
if (response.code() == 200) {
return createStatus(response);
}
throw new MastodonException(response);
} catch (IOException e) {
throw new MastodonException(e);
}

View File

@ -722,7 +722,7 @@ public class TwitterV1 implements Connection {
@Override
public void uploadStatus(StatusUpdate update, long[] mediaIds) throws TwitterException {
public Status uploadStatus(StatusUpdate update, long[] mediaIds) throws TwitterException {
List<String> params = new ArrayList<>();
if (update.getText() != null)
params.add("status=" + StringUtils.encode(update.getText()));
@ -743,7 +743,7 @@ public class TwitterV1 implements Connection {
params.add("lat=" + StringUtils.encode(lat));
params.add("long=" + StringUtils.encode(lon));
}
getTweet(TWEET_UPLOAD, params);
return getTweet(TWEET_UPLOAD, params);
}

View File

@ -10,6 +10,7 @@ import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.api.ConnectionManager;
import org.nuclearfog.twidda.backend.helper.MediaStatus;
import org.nuclearfog.twidda.backend.helper.StatusUpdate;
import org.nuclearfog.twidda.model.Status;
import org.nuclearfog.twidda.ui.activities.StatusEditor;
/**
@ -41,16 +42,16 @@ public class StatusUpdater extends AsyncExecutor<StatusUpdate, StatusUpdater.Sta
mediaIds[pos] = connection.uploadMedia(mediaUpdates[pos]);
}
// upload status
connection.uploadStatus(update, mediaIds);
return new StatusUpdateResult(true, null);
Status status = connection.uploadStatus(update, mediaIds);
return new StatusUpdateResult(status, null);
} catch (ConnectionException exception) {
return new StatusUpdateResult(false, exception);
return new StatusUpdateResult(null, exception);
} catch (Exception e) {
e.printStackTrace();
} finally {
update.close();
}
return new StatusUpdateResult(false, null);
return new StatusUpdateResult(null, null);
}
/**
@ -58,12 +59,13 @@ public class StatusUpdater extends AsyncExecutor<StatusUpdate, StatusUpdater.Sta
*/
public static class StatusUpdateResult {
public final boolean success;
@Nullable
public final Status status;
@Nullable
public final ConnectionException exception;
StatusUpdateResult(boolean success, @Nullable ConnectionException exception) {
this.success = success;
StatusUpdateResult(@Nullable Status status, @Nullable ConnectionException exception) {
this.status = status;
this.exception = exception;
}
}

View File

@ -63,25 +63,51 @@ public class StatusUpdate implements Serializable {
private static final String MIME_IMAGE_ALL = "image/";
private static final String MIME_VIDEO_ALL = "video/";
private long replyId;
@Nullable
// main attributes
private long statusId = 0L;
private long replyId = 0L;
private boolean sensitive = false;
private boolean spoiler = false;
private int visibility = Status.VISIBLE_PUBLIC;
private String text;
// attachment attributes
@Nullable
private PollUpdate poll;
@Nullable
private LocationUpdate location;
private MediaStatus[] mediaUpdates = {};
private int attachment = EMPTY;
// helper attributes
@Nullable
private Instance instance;
private List<String> mediaUriStrings = new ArrayList<>(5);
private Set<String> supportedFormats = new TreeSet<>();
private MediaStatus[] mediaUpdates = {};
private boolean attachmentLimitReached = false;
private boolean sensitive = false;
private boolean spoiler = false;
private int visibility = Status.VISIBLE_PUBLIC;
private int attachment = EMPTY;
/**
* set existing status to edit
*
* @param status existing status
*/
public void setStatus(Status status) {
statusId = status.getId();
replyId = status.getRepliedStatusId();
text = status.getText();
sensitive = status.isSensitive();
spoiler = status.isSpoiler();
visibility = status.getVisibility();
}
/**
* to edit an existing status, the ID can added
*
* @param statusId ID of an existing status to edit
*/
public void addStatusId(long statusId) {
this.statusId = statusId;
}
/**
* set ID of the replied status
@ -226,6 +252,22 @@ public class StatusUpdate implements Serializable {
this.instance = instance;
}
/**
* @return true to edit an existing status {@link #statusId} must be set
*/
public boolean statusExists() {
return statusId != 0L;
}
/**
* get ID of an existing status to edit
*
* @return status ID or '0' to post a new status instead of edit
*/
public long getStatusId() {
return statusId;
}
/**
* get ID of the replied status
*

View File

@ -46,6 +46,7 @@ public enum Configuration {
private final boolean statusVisibilitySupported;
private final boolean directMessageSupported;
private final boolean emojiSupported;
private final boolean statusEditSupported;
private final int arrayResHome;
/**
@ -69,6 +70,7 @@ public enum Configuration {
statusVisibilitySupported = false;
directMessageSupported = true;
emojiSupported = false;
statusEditSupported = false;
arrayResHome = R.array.home_twitter_icons;
break;
@ -87,6 +89,7 @@ public enum Configuration {
statusVisibilitySupported = true;
directMessageSupported = false;
emojiSupported = true;
statusEditSupported = true;
arrayResHome = R.array.home_mastodon_icons;
break;
}
@ -190,6 +193,13 @@ public enum Configuration {
return emojiSupported;
}
/**
* @return true if status edit is supported
*/
public boolean isStatusEditSupported() {
return statusEditSupported;
}
/**
* get home tabitems drawable IDs
*

View File

@ -2,6 +2,7 @@ package org.nuclearfog.twidda.ui.activities;
import static org.nuclearfog.twidda.ui.activities.SearchActivity.KEY_SEARCH_QUERY;
import static org.nuclearfog.twidda.ui.activities.StatusEditor.KEY_STATUS_EDITOR_DATA;
import static org.nuclearfog.twidda.ui.activities.StatusEditor.KEY_STATUS_EDITOR_EDIT;
import static org.nuclearfog.twidda.ui.activities.UsersActivity.KEY_USERS_ID;
import static org.nuclearfog.twidda.ui.activities.UsersActivity.KEY_USERS_MODE;
import static org.nuclearfog.twidda.ui.activities.UsersActivity.USERS_FAVORIT;
@ -33,6 +34,10 @@ import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
@ -102,7 +107,7 @@ import jp.wasabeef.picasso.transformations.RoundedCornersTransformation;
* @author nuclearfog
*/
public class StatusActivity extends AppCompatActivity implements OnClickListener, OnLongClickListener, OnTagClickListener,
OnConfirmListener, OnCardClickListener, OnScrollChangeListener, LockCallback {
OnConfirmListener, OnCardClickListener, OnScrollChangeListener, LockCallback, ActivityResultCallback<ActivityResult> {
/**
* Activity result code to update existing status information
@ -194,6 +199,7 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
*/
private static final int MENU_GROUP_COPY = 0x157426;
private ActivityResultLauncher<Intent> activityResultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), this);
private AsyncCallback<StatusResult> statusCallback = this::onStatusResult;
private AsyncCallback<PollActionResult> pollResult = this::onPollResult;
private AsyncCallback<TranslationResult> translationResult = this::onTranslationResult;
@ -439,6 +445,7 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
MenuItem optCopy = m.findItem(R.id.menu_status_copy);
MenuItem optMetrics = m.findItem(R.id.menu_status_metrics);
MenuItem menuBookmark = m.findItem(R.id.menu_status_bookmark);
MenuItem editStatus = m.findItem(R.id.menu_status_edit);
SubMenu copyMenu = optCopy.getSubMenu();
// set status options
@ -462,6 +469,9 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
// enable/disable status hide option
if (currentStatus.getAuthor().isCurrentUser()) {
optDelete.setVisible(true);
if (settings.getLogin().getConfiguration().isStatusEditSupported()) {
editStatus.setVisible(true);
}
}
// enable/disable status metrics option
if (currentStatus.getMetrics() != null) {
@ -496,7 +506,7 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
return true;
}
// add/remove bookmark
if (item.getItemId() == R.id.menu_status_bookmark) {
else if (item.getItemId() == R.id.menu_status_bookmark) {
Toast.makeText(getApplicationContext(), R.string.info_loading, Toast.LENGTH_SHORT).show();
int mode = status.isBookmarked() ? StatusParam.UNBOOKMARK : StatusParam.BOOKMARK;
StatusParam param = new StatusParam(mode, status.getId());
@ -557,10 +567,28 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
}
return true;
}
// edit status
else if (item.getItemId() == R.id.menu_status_edit) {
Intent intent = new Intent(this, StatusEditor.class);
intent.putExtra(KEY_STATUS_EDITOR_DATA, status);
intent.putExtra(KEY_STATUS_EDITOR_EDIT, true);
activityResultLauncher.launch(intent);
}
return super.onOptionsItemSelected(item);
}
@Override
public void onActivityResult(ActivityResult result) {
if (result.getData() != null && result.getResultCode() == StatusEditor.RETURN_STATUS_UPDATE) {
Serializable data = result.getData().getSerializableExtra(StatusEditor.RETURN_STATUS_DATA);
if (data instanceof Status) {
setStatus((Status) data);
}
}
}
@Override
public void onClick(View v) {
if (status != null) {
@ -835,14 +863,12 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
} else {
statusApi.setVisibility(View.GONE);
}
if (statusText.getText().length() == 0) {
if (!status.getText().isEmpty()) {
spannableText = Tagger.makeTextWithLinks(status.getText(), settings.getHighlightColor(), this);
statusText.setVisibility(View.VISIBLE);
statusText.setText(spannableText);
} else {
statusText.setVisibility(View.GONE);
}
if (!status.getText().isEmpty()) {
spannableText = Tagger.makeTextWithLinks(status.getText(), settings.getHighlightColor(), this);
statusText.setVisibility(View.VISIBLE);
statusText.setText(spannableText);
} else {
statusText.setVisibility(View.GONE);
}
if (status.getRepliedStatusId() > 0) {
if (!status.getReplyName().isEmpty())

View File

@ -55,18 +55,35 @@ import java.io.Serializable;
public class StatusEditor extends MediaActivity implements OnClickListener, OnProgressStopListener, OnConfirmListener,
OnMediaClickListener, TextWatcher, PollUpdateCallback, OnEmojiSelectListener {
/**
* return code used to send status information to calling activity
*/
public static final int RETURN_STATUS_UPDATE = 0x30220;
/**
* key to add the status to reply
* value type is {@link Status}
*/
public static final String KEY_STATUS_EDITOR_DATA = "status_data";
/**
* key to edit an existing status
* value type is Boolean
*/
public static final String KEY_STATUS_EDITOR_EDIT = "status_edit";
/**
* key for the text added to the status if any
* value type is String
*/
public static final String KEY_STATUS_EDITOR_TEXT = "status_text";
/**
* key to return uploaded status information
* value type is {@link Status}
*/
public static final String RETURN_STATUS_DATA = "status_update";
/**
* key for status update to restore
* value type is {@link StatusUpdate}
@ -103,8 +120,8 @@ public class StatusEditor extends MediaActivity implements OnClickListener, OnPr
@Override
protected void onCreate(@Nullable Bundle b) {
super.onCreate(b);
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.popup_status);
ViewGroup root = findViewById(R.id.popup_status_root);
ImageView background = findViewById(R.id.popup_status_background);
@ -134,20 +151,32 @@ public class StatusEditor extends MediaActivity implements OnClickListener, OnPr
if (!settings.getLogin().getConfiguration().isEmojiSupported()) {
emojiButton.setVisibility(View.GONE);
}
long replyId = 0L;
String prefix;
Serializable serializedStatus = getIntent().getSerializableExtra(KEY_STATUS_EDITOR_DATA);
if (serializedStatus instanceof Status) {
Status status = (Status) serializedStatus;
replyId = status.getId();
statusUpdate.setVisibility(status.getVisibility());
prefix = status.getUserMentions();
} else {
prefix = getIntent().getStringExtra(KEY_STATUS_EDITOR_TEXT);
}
statusUpdate.addReplyStatusId(replyId);
if (prefix != null) {
statusText.append(prefix);
// fetch parameters
if (savedInstanceState == null)
savedInstanceState = getIntent().getExtras();
if (savedInstanceState != null) {
Serializable serializedStatus = savedInstanceState.getSerializable(KEY_STATUS_EDITOR_DATA);
Serializable serializedStatusUpdate = savedInstanceState.getSerializable(KEY_STATUS_UPDATE);
boolean editStatus = savedInstanceState.getBoolean(KEY_STATUS_EDITOR_EDIT, false);
String prefix = savedInstanceState.getString(KEY_STATUS_EDITOR_TEXT);
if (serializedStatusUpdate instanceof StatusUpdate) {
statusUpdate = (StatusUpdate) serializedStatusUpdate;
} else if (serializedStatus instanceof Status) {
Status status = (Status) serializedStatus;
if (editStatus) {
statusUpdate.setStatus(status);
statusText.append(status.getText());
} else {
statusUpdate.addStatusId(status.getId());
statusUpdate.addReplyStatusId(status.getId());
statusUpdate.setVisibility(status.getVisibility());
statusUpdate.addText(status.getUserMentions());
statusText.append(status.getUserMentions());
}
} else {
statusUpdate.addText(prefix);
statusText.append(prefix);
}
}
adapter = new IconAdapter(settings, true);
adapter.addOnMediaClickListener(this);
@ -192,16 +221,6 @@ public class StatusEditor extends MediaActivity implements OnClickListener, OnPr
}
@Override
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Serializable serializedStatusUpdate = savedInstanceState.getSerializable(KEY_STATUS_UPDATE);
if (serializedStatusUpdate instanceof StatusUpdate) {
statusUpdate = (StatusUpdate) serializedStatusUpdate;
}
}
@Override
public void onBackPressed() {
showClosingMsg();
@ -399,7 +418,10 @@ public class StatusEditor extends MediaActivity implements OnClickListener, OnPr
* called when the status was successfully updated
*/
private void onStatusUpdated(@NonNull StatusUpdateResult result) {
if (result.success) {
if (result.status != null) {
Intent intent = new Intent();
intent.putExtra(RETURN_STATUS_DATA, result.status);
setResult(RETURN_STATUS_UPDATE, intent);
Toast.makeText(getApplicationContext(), R.string.info_status_sent, Toast.LENGTH_LONG).show();
finish();
} else {

View File

@ -34,6 +34,11 @@
android:title="@string/menu_status_hide"
android:visible="false" />
<item
android:id="@+id/menu_status_edit"
android:title="@string/menu_status_edit"
android:visible="false" />
<item
android:id="@+id/menu_status_delete"
android:title="@string/menu_status_delete"

View File

@ -130,6 +130,7 @@
<string name="menu_bookmark_remove">remove bookmark</string>
<string name="menu_unmute_user">unmute</string>
<string name="menu_follow_requested">follow requested</string>
<string name="menu_status_edit">edit</string>
<string name="menu_status_delete">delete</string>
<string name="menu_status_hide">hide</string>
<string name="menu_status_metrics">Metrics</string>