From f048eea4e1130c53792d55e6998093f091697439 Mon Sep 17 00:00:00 2001 From: stom79 Date: Sun, 20 Jan 2019 15:20:07 +0100 Subject: [PATCH] Schedule update remove --- .../mastodon/activities/TootActivity.java | 178 +++++++++++++++++- .../asynctasks/PostActionAsyncTask.java | 16 +- .../asynctasks/RetrieveFeedsAsyncTask.java | 2 +- .../fr/gouv/etalab/mastodon/client/API.java | 72 +++---- .../mastodon/client/Entities/Schedule.java | 38 +++- .../client/Entities/StoredStatus.java | 67 ++++++- .../drawers/ScheduledTootsListAdapter.java | 115 +++++++---- .../DisplayScheduledTootsFragment.java | 99 +++++----- app/src/main/res/values/strings.xml | 1 + 9 files changed, 459 insertions(+), 129 deletions(-) diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/activities/TootActivity.java b/app/src/main/java/fr/gouv/etalab/mastodon/activities/TootActivity.java index 0190994e7..ffb685ec3 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/activities/TootActivity.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/activities/TootActivity.java @@ -102,12 +102,14 @@ import java.util.regex.Pattern; import es.dmoral.toasty.Toasty; import fr.gouv.etalab.mastodon.R; +import fr.gouv.etalab.mastodon.asynctasks.PostActionAsyncTask; import fr.gouv.etalab.mastodon.asynctasks.PostStatusAsyncTask; import fr.gouv.etalab.mastodon.asynctasks.RetrieveAccountsForReplyAsyncTask; import fr.gouv.etalab.mastodon.asynctasks.RetrieveEmojiAsyncTask; import fr.gouv.etalab.mastodon.asynctasks.RetrieveSearchAccountsAsyncTask; import fr.gouv.etalab.mastodon.asynctasks.RetrieveSearchAsyncTask; import fr.gouv.etalab.mastodon.asynctasks.UpdateDescriptionAttachmentAsyncTask; +import fr.gouv.etalab.mastodon.client.API; import fr.gouv.etalab.mastodon.client.APIResponse; import fr.gouv.etalab.mastodon.client.Entities.Account; import fr.gouv.etalab.mastodon.client.Entities.Attachment; @@ -129,6 +131,7 @@ import fr.gouv.etalab.mastodon.drawers.TagsSearchAdapter; import fr.gouv.etalab.mastodon.helper.Helper; import fr.gouv.etalab.mastodon.helper.MastalabAutoCompleteTextView; import fr.gouv.etalab.mastodon.interfaces.OnDownloadInterface; +import fr.gouv.etalab.mastodon.interfaces.OnPostActionInterface; import fr.gouv.etalab.mastodon.interfaces.OnPostStatusActionInterface; import fr.gouv.etalab.mastodon.interfaces.OnRetrieveAccountsReplyInterface; import fr.gouv.etalab.mastodon.interfaces.OnRetrieveAttachmentInterface; @@ -152,7 +155,7 @@ import static fr.gouv.etalab.mastodon.helper.Helper.convertDpToPixel; * Toot activity class */ -public class TootActivity extends BaseActivity implements OnRetrieveSearcAccountshInterface, OnRetrieveAttachmentInterface, OnPostStatusActionInterface, OnRetrieveSearchInterface, OnRetrieveAccountsReplyInterface, OnRetrieveEmojiInterface, OnDownloadInterface { +public class TootActivity extends BaseActivity implements OnPostActionInterface, OnRetrieveSearcAccountshInterface, OnRetrieveAttachmentInterface, OnPostStatusActionInterface, OnRetrieveSearchInterface, OnRetrieveAccountsReplyInterface, OnRetrieveEmojiInterface, OnDownloadInterface { private String visibility; @@ -198,7 +201,8 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount private boolean restoredScheduled; static boolean active = false; private int style; - + private StoredStatus scheduledstatus; + private boolean isScheduled; @Override protected void onCreate(Bundle savedInstanceState) { @@ -275,7 +279,7 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount toot_sensitive = findViewById(R.id.toot_sensitive); drawer_layout = findViewById(R.id.drawer_layout); ImageButton toot_emoji = findViewById(R.id.toot_emoji); - + isScheduled = false; if( sharedpreferences.getBoolean(Helper.SET_DISPLAY_EMOJI, true)) { final EmojiPopup emojiPopup = EmojiPopup.Builder.fromRootView(drawer_layout).build(toot_content); @@ -315,6 +319,7 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount restored = -1; if(b != null) { tootReply = b.getParcelable("tootReply"); + scheduledstatus = b.getParcelable("storedStatus"); String accountReplyToken = b.getString("accountReplyToken", null); accountReply = null; if( accountReplyToken != null){ @@ -348,7 +353,8 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount } restored = b.getLong("restored", -1); } - + if( scheduledstatus != null) + toot_it.setText(R.string.modify); if(restoredScheduled){ toot_it.setVisibility(View.GONE); invalidateOptionsMenu(); @@ -627,6 +633,8 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount } }); + if( scheduledstatus != null) + restoreServerSchedule(scheduledstatus.getStatus()); if( restored != -1 ){ restoreToot(restored); @@ -768,6 +776,16 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount } } + @Override + public void onPostAction(int statusCode, API.StatusAction statusAction, String userId, Error error) { + if( error != null){ + Toasty.error(getApplicationContext(),getString(R.string.toast_error),Toast.LENGTH_LONG).show(); + }else { + Toasty.success(getApplicationContext(),getString(R.string.toot_scheduled),Toast.LENGTH_LONG).show(); + resetForNextToot(); + } + } + private class asyncPicture extends AsyncTask { ByteArrayInputStream bs; @@ -1273,7 +1291,7 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount private void sendToot(String timestamp){ toot_it.setEnabled(false); if(toot_content.getText().toString().trim().length() == 0 && attachments.size() == 0){ - Toasty.error(getApplicationContext(),getString(R.string.toot_select_image_error),Toast.LENGTH_LONG).show(); + Toasty.error(getApplicationContext(),getString(R.string.toot_error_no_content),Toast.LENGTH_LONG).show(); toot_it.setEnabled(true); return; } @@ -1301,7 +1319,15 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount toot.setContent(tootContent); if( timestamp == null) - new PostStatusAsyncTask(getApplicationContext(), accountReply, toot, TootActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + if( scheduledstatus == null) + new PostStatusAsyncTask(getApplicationContext(), accountReply, toot, TootActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + else { + toot.setScheduled_at(Helper.dateToString(scheduledstatus.getScheduled_date())); + scheduledstatus.setStatus(toot); + isScheduled = true; + new PostActionAsyncTask(getApplicationContext(), API.StatusAction.DELETESCHEDULED, scheduledstatus, TootActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + new PostStatusAsyncTask(getApplicationContext(), accountReply, toot, TootActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } else { toot.setScheduled_at(timestamp); new PostStatusAsyncTask(getApplicationContext(), accountReply, toot, TootActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); @@ -1312,12 +1338,14 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount private void serverSchedule(String time){ sendToot(time); + isScheduled = true; resetForNextToot(); } private void deviceSchedule(long time){ //Store the toot as draft first storeToot(false, false); + isScheduled = true; //Schedules the toot ScheduledTootsSyncJob.schedule(getApplicationContext(), currentToId, time); resetForNextToot(); @@ -1730,7 +1758,10 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount isSensitive = false; toot_sensitive.setVisibility(View.GONE); currentToId = -1; - Toasty.success(TootActivity.this, getString(R.string.toot_sent), Toast.LENGTH_LONG).show(); + if( scheduledstatus == null && !isScheduled) + Toasty.success(TootActivity.this, getString(R.string.toot_sent), Toast.LENGTH_LONG).show(); + else + Toasty.success(TootActivity.this, getString(R.string.toot_scheduled), Toast.LENGTH_LONG).show(); toot_it.setEnabled(true); //It's a reply, so the user will be redirect to its answer if( tootReply != null){ @@ -2069,6 +2100,139 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount } + private void restoreServerSchedule(Status status){ + + attachments = status.getMedia_attachments(); + int childCount = toot_picture_container.getChildCount(); + ArrayList toRemove = new ArrayList<>(); + if( childCount > 0 ){ + for(int i = 0 ; i < childCount ; i++){ + if( toot_picture_container.getChildAt(i) instanceof ImageView) + toRemove.add((ImageView)toot_picture_container.getChildAt(i)); + } + if( toRemove.size() > 0){ + for(ImageView imageView: toRemove) + toot_picture_container.removeView(imageView); + } + toRemove.clear(); + } + String content = status.getContent(); + Pattern mentionLink = Pattern.compile("(<\\s?a\\s?href=\"https?:\\/\\/([\\da-z\\.-]+\\.[a-z\\.]{2,10})\\/(@[\\/\\w._-]*)\"\\s?[^.]*<\\s?\\/\\s?a\\s?>)"); + Matcher matcher = mentionLink.matcher(content); + if (matcher.find()) { + content = matcher.replaceAll("$3@$2"); + } + if( removed ) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) + content = Html.fromHtml(content, Html.FROM_HTML_MODE_LEGACY).toString(); + else + //noinspection deprecation + content = Html.fromHtml(content).toString(); + } + if( attachments != null && attachments.size() > 0){ + toot_picture_container.setVisibility(View.VISIBLE); + picture_scrollview.setVisibility(View.VISIBLE); + int i = 0 ; + for(final Attachment attachment: attachments){ + String url = attachment.getPreview_url(); + if( url == null || url.trim().equals("")) + url = attachment.getUrl(); + final ImageView imageView = new ImageView(getApplicationContext()); + imageView.setId(Integer.parseInt(attachment.getId())); + + LinearLayout.LayoutParams imParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT); + imParams.setMargins(20, 5, 20, 5); + imParams.height = (int) Helper.convertDpToPixel(100, getApplicationContext()); + imageView.setAdjustViewBounds(true); + imageView.setScaleType(ImageView.ScaleType.FIT_XY); + toot_picture_container.addView(imageView, i, imParams); + + Glide.with(imageView.getContext()) + .asBitmap() + .load(url) + .into(new SimpleTarget() { + @Override + public void onResourceReady(@NonNull Bitmap resource, Transition transition) { + imageView.setImageBitmap(resource); + } + }); + imageView.setTag(attachment.getId()); + imageView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE); + String instanceVersion = sharedpreferences.getString(Helper.INSTANCE_VERSION + userId + instance, null); + if (instanceVersion != null) { + Version currentVersion = new Version(instanceVersion); + Version minVersion = new Version("2.0"); + if (currentVersion.compareTo(minVersion) == 1 || currentVersion.equals(minVersion)) { + imageView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + showAddDescription(attachment); + } + }); + } + } + } + }); + imageView.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View view) { + showRemove(imageView.getId()); + return false; + } + }); + addBorder(); + if( attachments.size() < 4) + toot_picture.setEnabled(true); + toot_sensitive.setVisibility(View.VISIBLE); + i++; + } + }else { + toot_picture_container.setVisibility(View.GONE); + } + //Sensitive content + toot_sensitive.setChecked(status.isSensitive()); + if( status.getSpoiler_text() != null && status.getSpoiler_text().length() > 0 ){ + toot_cw_content.setText(status.getSpoiler_text()); + toot_cw_content.setVisibility(View.VISIBLE); + }else { + toot_cw_content.setText(""); + toot_cw_content.setVisibility(View.GONE); + } + + toot_content.setText(content); + toot_space_left.setText(String.valueOf(toot_content.length())); + toot_content.setSelection(toot_content.getText().length()); + switch (status.getVisibility()){ + case "public": + visibility = "public"; + toot_visibility.setImageResource(R.drawable.ic_public_toot); + break; + case "unlisted": + visibility = "unlisted"; + toot_visibility.setImageResource(R.drawable.ic_lock_open_toot); + break; + case "private": + visibility = "private"; + toot_visibility.setImageResource(R.drawable.ic_lock_outline_toot); + break; + case "direct": + visibility = "direct"; + toot_visibility.setImageResource(R.drawable.ic_mail_outline_toot); + break; + } + + if( title != null) + title.setText(getString(R.string.toot_title)); + else + setTitle(R.string.toot_title); + invalidateOptionsMenu(); + initialContent = toot_content.getText().toString(); + toot_space_left.setText(String.valueOf(toot_content.getText().length() + toot_cw_content.getText().length())); + } + private void tootReply(){ SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE); if( title != null) diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/PostActionAsyncTask.java b/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/PostActionAsyncTask.java index 727da13b6..35a295b52 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/PostActionAsyncTask.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/PostActionAsyncTask.java @@ -25,6 +25,7 @@ import fr.gouv.etalab.mastodon.client.API; import fr.gouv.etalab.mastodon.client.Entities.Account; import fr.gouv.etalab.mastodon.client.Entities.Error; import fr.gouv.etalab.mastodon.client.Entities.Results; +import fr.gouv.etalab.mastodon.client.Entities.StoredStatus; import fr.gouv.etalab.mastodon.client.PeertubeAPI; import fr.gouv.etalab.mastodon.helper.Helper; import fr.gouv.etalab.mastodon.interfaces.OnPostActionInterface; @@ -48,6 +49,14 @@ public class PostActionAsyncTask extends AsyncTask { private WeakReference contextReference; private boolean muteNotifications; private Error error; + private StoredStatus storedStatus; + + public PostActionAsyncTask(Context context, API.StatusAction apiAction, StoredStatus storedStatus, OnPostActionInterface onPostActionInterface){ + this.contextReference = new WeakReference<>(context); + this.listener = onPostActionInterface; + this.apiAction = apiAction; + this.storedStatus = storedStatus; + } public PostActionAsyncTask(Context context, API.StatusAction apiAction, String targetedId, OnPostActionInterface onPostActionInterface){ this.contextReference = new WeakReference<>(context); @@ -154,7 +163,12 @@ public class PostActionAsyncTask extends AsyncTask { statusCode = api.reportAction(status, comment); else if (apiAction == API.StatusAction.CREATESTATUS) statusCode = api.statusAction(status); - else if (apiAction == API.StatusAction.MUTE_NOTIFICATIONS) + else if(apiAction == API.StatusAction.UPDATESERVERSCHEDULE) { + api.scheduledAction("PUT", storedStatus.getStatus(), null, storedStatus.getScheduledServerdId()); + } + else if(apiAction == API.StatusAction.DELETESCHEDULED) { + api.scheduledAction("DELETE", null, null, storedStatus.getScheduledServerdId()); + }else if (apiAction == API.StatusAction.MUTE_NOTIFICATIONS) statusCode = api.muteNotifications(targetedId, muteNotifications); else statusCode = api.postAction(apiAction, targetedId); diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveFeedsAsyncTask.java b/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveFeedsAsyncTask.java index 8855b2b78..5fd4d78cd 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveFeedsAsyncTask.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveFeedsAsyncTask.java @@ -170,7 +170,7 @@ public class RetrieveFeedsAsyncTask extends AsyncTask { apiResponse = api.getPublicTimeline(false, max_id); break; case SCHEDULED_TOOTS: - apiResponse = api.scheduledAction("GET", null, max_id); + apiResponse = api.scheduledAction("GET", null, max_id, null); break; case DIRECT: apiResponse = api.getDirectTimeline(max_id); diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java b/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java index 254db6b55..b95181034 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java @@ -120,7 +120,9 @@ public class API { PEERTUBECOMMENT, PEERTUBEREPLY, PEERTUBEDELETECOMMENT, - PEERTUBEDELETEVIDEO + PEERTUBEDELETEVIDEO, + UPDATESERVERSCHEDULE, + DELETESCHEDULED } public enum accountPrivacy { @@ -1856,33 +1858,12 @@ public class API { * @param status Status object related to the status * @return APIResponse */ - public APIResponse scheduledAction(String call, Status status, String max_id){ + public APIResponse scheduledAction(String call, Status status, String max_id, String targetedId){ HashMap params = new HashMap<>(); if( call.equals("PUT")){ - try { - params.put("status", URLEncoder.encode(status.getContent(), "UTF-8")); - } catch (UnsupportedEncodingException e) { - params.put("status", status.getContent()); - } - if( status.getIn_reply_to_id() != null) - params.put("in_reply_to_id", status.getIn_reply_to_id()); - if( status.getMedia_attachments() != null && status.getMedia_attachments().size() > 0 ) { - StringBuilder parameters = new StringBuilder(); - for(Attachment attachment: status.getMedia_attachments()) - parameters.append("media_ids[]=").append(attachment.getId()).append("&"); - parameters = new StringBuilder(parameters.substring(0, parameters.length() - 1).substring(12)); - params.put("media_ids[]", parameters.toString()); - } - if( status.isSensitive()) - params.put("sensitive", Boolean.toString(status.isSensitive())); - if( status.getSpoiler_text() != null) - try { - params.put("spoiler_text", URLEncoder.encode(status.getSpoiler_text(), "UTF-8")); - } catch (UnsupportedEncodingException e) { - params.put("spoiler_text", status.getSpoiler_text()); - } - params.put("visibility", status.getVisibility()); + if( status.getScheduled_at() != null) + params.put("scheduled_at", status.getScheduled_at()); }else if(call.equals("GET")){ if( max_id != null ) params.put("max_id", max_id); @@ -1891,30 +1872,30 @@ public class API { try { HttpsConnection httpsConnection = new HttpsConnection(context); String response = null; - int responseCode; + int responseCode = -1; if( call.equals("GET")) response = httpsConnection.get(getAbsoluteUrl("/scheduled_statuses/"), 60, null, prefKeyOauthTokenT); else if( call.equals("PUT")) - response = httpsConnection.get(getAbsoluteUrl(String.format("/scheduled_statuses/%s", status.getId())), 60, params, prefKeyOauthTokenT); + response = httpsConnection.put(getAbsoluteUrl(String.format("/scheduled_statuses/%s", targetedId)), 60, params, prefKeyOauthTokenT); else if( call.equals("DELETE")) - responseCode = httpsConnection.delete(getAbsoluteUrl(String.format("/scheduled_statuses/%s", status.getId())), 60, params, prefKeyOauthTokenT); + responseCode = httpsConnection.delete(getAbsoluteUrl(String.format("/scheduled_statuses/%s",targetedId)), 60, null, prefKeyOauthTokenT); if(call.equals("GET")) { apiResponse.setSince_id(httpsConnection.getSince_id()); apiResponse.setMax_id(httpsConnection.getMax_id()); } if (response != null && call.equals("PUT")) { - Status statusreturned = parseStatuses(context, new JSONObject(response)); + Schedule schedule = parseSimpleSchedule(context, new JSONObject(response)); StoredStatus st = new StoredStatus(); st.setCreation_date(status.getCreated_at()); st.setId(-1); st.setJobId(-1); - st.setScheduled_date(new Date(Long.parseLong(status.getScheduled_at()))); + st.setScheduled_date(schedule.getScheduled_at()); st.setStatusReply(null); st.setSent_date(null); final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); st.setUserId(userId); - st.setStatus(statusreturned); + st.setStatus(schedule.getStatus()); storedStatus.add(st); }else if (response != null && call.equals("GET")) { List scheduleList = parseSchedule(context, new JSONArray(response)); @@ -1923,7 +1904,7 @@ public class API { for(Schedule schedule: scheduleList){ StoredStatus st = new StoredStatus(); st.setCreation_date(null); - st.setId(-1); + st.setScheduledServerdId(schedule.getId()); st.setJobId(-1); st.setScheduled_date(schedule.getScheduled_at()); st.setStatusReply(null); @@ -3196,6 +3177,29 @@ public class API { return conversation; } + /** + * Parse json response for several scheduled toots + * @param jsonObject JSONObject + * @return List + */ + private static Schedule parseSimpleSchedule(Context context, JSONObject jsonObject){ + Schedule schedule = new Schedule(); + try { + JSONObject resobj = jsonObject.getJSONObject("params"); + Status status = parseSchedule(context, resobj); + List attachements = parseAttachmentResponse(jsonObject.getJSONArray("media_attachments")); + status.setMedia_attachments((ArrayList) attachements); + schedule.setStatus(status); + schedule.setAttachmentList(attachements); + schedule.setId(jsonObject.get("id").toString()); + schedule.setScheduled_at(Helper.mstStringToDate(context, jsonObject.get("scheduled_at").toString())); + } catch (JSONException e) { + e.printStackTrace(); + } catch (ParseException e) { + e.printStackTrace(); + } + return schedule; + } /** * Parse json response for several scheduled toots @@ -3217,11 +3221,13 @@ public class API { schedule.setAttachmentList(attachements); schedules.add(schedule); schedule.setId(jsonArray.getJSONObject(i).get("id").toString()); - schedule.setScheduled_at(Helper.stringToDate(context, resobj.get("scheduled_at").toString())); + schedule.setScheduled_at(Helper.mstStringToDate(context, jsonArray.getJSONObject(i).get("scheduled_at").toString())); i++; } } catch (JSONException e) { e.printStackTrace(); + } catch (ParseException e) { + e.printStackTrace(); } return schedules; } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/Schedule.java b/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/Schedule.java index 6013e4c9d..11de94c1e 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/Schedule.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/Schedule.java @@ -15,6 +15,9 @@ package fr.gouv.etalab.mastodon.client.Entities; +import android.os.Parcel; +import android.os.Parcelable; + import java.util.Date; import java.util.List; @@ -23,7 +26,7 @@ import java.util.List; * Manages scheduled toots */ -public class Schedule { +public class Schedule implements Parcelable { private String id; private Date scheduled_at; @@ -64,4 +67,37 @@ public class Schedule { public void setAttachmentList(List attachmentList) { this.attachmentList = attachmentList; } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(this.id); + dest.writeLong(this.scheduled_at != null ? this.scheduled_at.getTime() : -1); + dest.writeParcelable(this.status, flags); + dest.writeTypedList(this.attachmentList); + } + + protected Schedule(Parcel in) { + this.id = in.readString(); + long tmpScheduled_at = in.readLong(); + this.scheduled_at = tmpScheduled_at == -1 ? null : new Date(tmpScheduled_at); + this.status = in.readParcelable(Status.class.getClassLoader()); + this.attachmentList = in.createTypedArrayList(Attachment.CREATOR); + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public Schedule createFromParcel(Parcel source) { + return new Schedule(source); + } + + @Override + public Schedule[] newArray(int size) { + return new Schedule[size]; + } + }; } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/StoredStatus.java b/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/StoredStatus.java index 82d0c428b..6062fbad6 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/StoredStatus.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/StoredStatus.java @@ -1,5 +1,8 @@ package fr.gouv.etalab.mastodon.client.Entities; +import android.os.Parcel; +import android.os.Parcelable; + import java.util.Date; @@ -8,7 +11,7 @@ import java.util.Date; * Manage Stored status */ -public class StoredStatus { +public class StoredStatus implements Parcelable { private int id; private Date creation_date; @@ -20,6 +23,7 @@ public class StoredStatus { private Status statusReply; private String instance; private String userId; + private String scheduledServerdId; public int getId() { return id; @@ -101,4 +105,65 @@ public class StoredStatus { public void setStatusReply(Status statusReply) { this.statusReply = statusReply; } + + + public String getScheduledServerdId() { + return scheduledServerdId; + } + + public void setScheduledServerdId(String scheduledServerdId) { + this.scheduledServerdId = scheduledServerdId; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(this.id); + dest.writeLong(this.creation_date != null ? this.creation_date.getTime() : -1); + dest.writeLong(this.scheduled_date != null ? this.scheduled_date.getTime() : -1); + dest.writeLong(this.sent_date != null ? this.sent_date.getTime() : -1); + dest.writeInt(this.jobId); + dest.writeByte(this.isSent ? (byte) 1 : (byte) 0); + dest.writeParcelable(this.status, flags); + dest.writeParcelable(this.statusReply, flags); + dest.writeString(this.instance); + dest.writeString(this.userId); + dest.writeString(this.scheduledServerdId); + } + + public StoredStatus() { + } + + protected StoredStatus(Parcel in) { + this.id = in.readInt(); + long tmpCreation_date = in.readLong(); + this.creation_date = tmpCreation_date == -1 ? null : new Date(tmpCreation_date); + long tmpScheduled_date = in.readLong(); + this.scheduled_date = tmpScheduled_date == -1 ? null : new Date(tmpScheduled_date); + long tmpSent_date = in.readLong(); + this.sent_date = tmpSent_date == -1 ? null : new Date(tmpSent_date); + this.jobId = in.readInt(); + this.isSent = in.readByte() != 0; + this.status = in.readParcelable(Status.class.getClassLoader()); + this.statusReply = in.readParcelable(Status.class.getClassLoader()); + this.instance = in.readString(); + this.userId = in.readString(); + this.scheduledServerdId = in.readString(); + } + + public static final Creator CREATOR = new Creator() { + @Override + public StoredStatus createFromParcel(Parcel source) { + return new StoredStatus(source); + } + + @Override + public StoredStatus[] newArray(int size) { + return new StoredStatus[size]; + } + }; } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/ScheduledTootsListAdapter.java b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/ScheduledTootsListAdapter.java index e9728f53b..8e0f298d8 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/ScheduledTootsListAdapter.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/ScheduledTootsListAdapter.java @@ -20,6 +20,7 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.database.sqlite.SQLiteDatabase; +import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.support.v7.app.AlertDialog; @@ -49,10 +50,14 @@ import fr.gouv.etalab.mastodon.R; import fr.gouv.etalab.mastodon.activities.MainActivity; import fr.gouv.etalab.mastodon.activities.ShowConversationActivity; import fr.gouv.etalab.mastodon.activities.TootActivity; +import fr.gouv.etalab.mastodon.asynctasks.PostActionAsyncTask; +import fr.gouv.etalab.mastodon.client.API; +import fr.gouv.etalab.mastodon.client.Entities.Error; import fr.gouv.etalab.mastodon.client.Entities.Status; import fr.gouv.etalab.mastodon.client.Entities.StoredStatus; import fr.gouv.etalab.mastodon.fragments.DisplayScheduledTootsFragment; import fr.gouv.etalab.mastodon.helper.Helper; +import fr.gouv.etalab.mastodon.interfaces.OnPostActionInterface; import fr.gouv.etalab.mastodon.jobs.ApplicationJob; import fr.gouv.etalab.mastodon.jobs.ScheduledBoostsSyncJob; import fr.gouv.etalab.mastodon.jobs.ScheduledTootsSyncJob; @@ -67,7 +72,7 @@ import static fr.gouv.etalab.mastodon.helper.Helper.changeDrawableColor; * Created by Thomas on 16/07/2017. * Adapter for scheduled toots */ -public class ScheduledTootsListAdapter extends BaseAdapter { +public class ScheduledTootsListAdapter extends BaseAdapter implements OnPostActionInterface { private Context context; private List storedStatuses; @@ -195,18 +200,27 @@ public class ScheduledTootsListAdapter extends BaseAdapter { .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - if( type == DisplayScheduledTootsFragment.typeOfSchedule.TOOT) - new StatusStoredDAO(context, db).remove(storedStatus.getId()); - else if (type == DisplayScheduledTootsFragment.typeOfSchedule.BOOST) - new BoostScheduleDAO(context, db).remove(storedStatus.getId()); - storedStatuses.remove(storedStatus); - scheduledTootsListAdapter.notifyDataSetChanged(); - if( storedStatuses.size() == 0 && textviewNoAction != null && textviewNoAction.getVisibility() == View.GONE) + if( type != DisplayScheduledTootsFragment.typeOfSchedule.SERVER) { + if (type == DisplayScheduledTootsFragment.typeOfSchedule.TOOT) + new StatusStoredDAO(context, db).remove(storedStatus.getId()); + else if (type == DisplayScheduledTootsFragment.typeOfSchedule.BOOST) + new BoostScheduleDAO(context, db).remove(storedStatus.getId()); + storedStatuses.remove(storedStatus); + scheduledTootsListAdapter.notifyDataSetChanged(); + if (storedStatuses.size() == 0 && textviewNoAction != null && textviewNoAction.getVisibility() == View.GONE) textviewNoAction.setVisibility(View.VISIBLE); - try { - //Cancel the job - ApplicationJob.cancelJob(storedStatus.getJobId()); - }catch (Exception ignored){} + try { + //Cancel the job + ApplicationJob.cancelJob(storedStatus.getJobId()); + } catch (Exception ignored) { + } + }else{ + new PostActionAsyncTask(context, API.StatusAction.DELETESCHEDULED, storedStatus, ScheduledTootsListAdapter.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + storedStatuses.remove(storedStatus); + scheduledTootsListAdapter.notifyDataSetChanged(); + if (storedStatuses.size() == 0 && textviewNoAction != null && textviewNoAction.getVisibility() == View.GONE) + textviewNoAction.setVisibility(View.VISIBLE); + } dialog.dismiss(); } }) @@ -221,10 +235,12 @@ public class ScheduledTootsListAdapter extends BaseAdapter { } }); - if (storedStatus.getJobId() > 0) { - holder.scheduled_toot_failed.setVisibility(View.GONE); - }else { - holder.scheduled_toot_failed.setVisibility(View.VISIBLE); + if( type != DisplayScheduledTootsFragment.typeOfSchedule.SERVER) { + if (storedStatus.getJobId() > 0) { + holder.scheduled_toot_failed.setVisibility(View.GONE); + } else { + holder.scheduled_toot_failed.setVisibility(View.VISIBLE); + } } holder.scheduled_toot_media_count.setText(context.getString(R.string.media_count, status.getMedia_attachments().size())); holder.scheduled_toot_date_creation.setText(Helper.dateToString(storedStatus.getCreation_date())); @@ -319,28 +335,35 @@ public class ScheduledTootsListAdapter extends BaseAdapter { Toasty.error(context, context.getString(R.string.toot_scheduled_date), Toast.LENGTH_LONG).show(); }else { //Schedules the toot to the new date - try { - //Removes the job - ApplicationJob.cancelJob(storedStatus.getJobId()); - //Replace it by the new one - StoredStatus storedStatusnew = null; - if( type == DisplayScheduledTootsFragment.typeOfSchedule.TOOT) { - ScheduledTootsSyncJob.schedule(context, storedStatus.getId(), time); - storedStatusnew = new StatusStoredDAO(context, db).getStatus(storedStatus.getId()); - }else if(type == DisplayScheduledTootsFragment.typeOfSchedule.BOOST){ - ScheduledBoostsSyncJob.scheduleUpdate(context, storedStatus.getId(), time); - storedStatusnew = new BoostScheduleDAO(context, db).getStatus(storedStatus.getId()); + if( type != DisplayScheduledTootsFragment.typeOfSchedule.SERVER) { + try { + //Removes the job + ApplicationJob.cancelJob(storedStatus.getJobId()); + //Replace it by the new one + StoredStatus storedStatusnew = null; + if (type == DisplayScheduledTootsFragment.typeOfSchedule.TOOT) { + ScheduledTootsSyncJob.schedule(context, storedStatus.getId(), time); + storedStatusnew = new StatusStoredDAO(context, db).getStatus(storedStatus.getId()); + } else if (type == DisplayScheduledTootsFragment.typeOfSchedule.BOOST) { + ScheduledBoostsSyncJob.scheduleUpdate(context, storedStatus.getId(), time); + storedStatusnew = new BoostScheduleDAO(context, db).getStatus(storedStatus.getId()); + } + //Date displayed is changed + assert storedStatusnew != null; + storedStatus.setScheduled_date(storedStatusnew.getScheduled_date()); + scheduledTootsListAdapter.notifyDataSetChanged(); + //Notifiy all is ok + if (type == DisplayScheduledTootsFragment.typeOfSchedule.TOOT) + Toasty.success(context, context.getString(R.string.toot_scheduled), Toast.LENGTH_LONG).show(); + else + Toasty.success(context, context.getString(R.string.boost_scheduled), Toast.LENGTH_LONG).show(); + } catch (Exception ignored) { } - //Date displayed is changed - assert storedStatusnew != null; - storedStatus.setScheduled_date(storedStatusnew.getScheduled_date()); - scheduledTootsListAdapter.notifyDataSetChanged(); - //Notifiy all is ok - if( type == DisplayScheduledTootsFragment.typeOfSchedule.TOOT) - Toasty.success(context,context.getString(R.string.toot_scheduled), Toast.LENGTH_LONG).show(); - else - Toasty.success(context,context.getString(R.string.boost_scheduled), Toast.LENGTH_LONG).show(); - }catch (Exception ignored){} + }else{ + storedStatus.getStatus().setScheduled_at(Helper.dateToString(calendar.getTime())); + new PostActionAsyncTask(context, API.StatusAction.UPDATESERVERSCHEDULE, storedStatus, ScheduledTootsListAdapter.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + Toasty.success(context, context.getString(R.string.boost_scheduled), Toast.LENGTH_LONG).show(); + } alertDialog.dismiss(); } } @@ -385,9 +408,27 @@ public class ScheduledTootsListAdapter extends BaseAdapter { context.startActivity(intentToot); } }); + else if( type == DisplayScheduledTootsFragment.typeOfSchedule.SERVER) + holder.scheduled_toot_container.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intentToot = new Intent(context, TootActivity.class); + Bundle b = new Bundle(); + if( storedStatus.getStatus().getSpoiler_text().equals("null")) + storedStatus.getStatus().setSpoiler_text(""); + b.putParcelable("storedStatus", storedStatus); + intentToot.putExtras(b); + context.startActivity(intentToot); + } + }); return convertView; } + @Override + public void onPostAction(int statusCode, API.StatusAction statusAction, String userId, Error error) { + + } + private class ViewHolder { LinearLayout scheduled_toot_container; TextView scheduled_toot_title; diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/fragments/DisplayScheduledTootsFragment.java b/app/src/main/java/fr/gouv/etalab/mastodon/fragments/DisplayScheduledTootsFragment.java index 38cf65f0b..b8014ef29 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/fragments/DisplayScheduledTootsFragment.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/fragments/DisplayScheduledTootsFragment.java @@ -135,56 +135,59 @@ public class DisplayScheduledTootsFragment extends Fragment implements OnRetriev @Override public void onResume(){ super.onResume(); - //Retrieves scheduled toots - asyncTask = new RetrieveScheduledTootsAsyncTask(context, type,DisplayScheduledTootsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - final PowerManager powerManager = (PowerManager) getActivity().getSystemService(Context.POWER_SERVICE); - final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); - //Battery saver is one and user never asked to stop showing the message - changeDrawableColor(context, R.drawable.ic_report, R.color.mastodonC4); - changeDrawableColor(context, R.drawable.ic_cancel, R.color.mastodonC4); - if( powerManager != null && powerManager.isPowerSaveMode() && sharedpreferences.getBoolean(Helper.SHOW_BATTERY_SAVER_MESSAGE,true)){ - warning_battery_message.setVisibility(View.VISIBLE); - }else { - warning_battery_message.setVisibility(View.GONE); - } - warning_battery_message.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - final int DRAWABLE_RIGHT = 2; - if(event.getAction() == MotionEvent.ACTION_UP) { - if(event.getRawX() >= (warning_battery_message.getRight() - warning_battery_message.getCompoundDrawables()[DRAWABLE_RIGHT].getBounds().width())) { - SharedPreferences.Editor editor = sharedpreferences.edit(); - editor.putBoolean(Helper.SHOW_BATTERY_SAVER_MESSAGE, false); - editor.apply(); - warning_battery_message.setVisibility(View.GONE); - return true; + if( type != null && type != typeOfSchedule.SERVER) { + //Retrieves scheduled toots + asyncTask = new RetrieveScheduledTootsAsyncTask(context, type, DisplayScheduledTootsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + final PowerManager powerManager = (PowerManager) getActivity().getSystemService(Context.POWER_SERVICE); + final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + //Battery saver is one and user never asked to stop showing the message + changeDrawableColor(context, R.drawable.ic_report, R.color.mastodonC4); + changeDrawableColor(context, R.drawable.ic_cancel, R.color.mastodonC4); + if (powerManager != null && powerManager.isPowerSaveMode() && sharedpreferences.getBoolean(Helper.SHOW_BATTERY_SAVER_MESSAGE, true)) { + warning_battery_message.setVisibility(View.VISIBLE); + } else { + warning_battery_message.setVisibility(View.GONE); + } + warning_battery_message.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + final int DRAWABLE_RIGHT = 2; + if (event.getAction() == MotionEvent.ACTION_UP) { + if (event.getRawX() >= (warning_battery_message.getRight() - warning_battery_message.getCompoundDrawables()[DRAWABLE_RIGHT].getBounds().width())) { + SharedPreferences.Editor editor = sharedpreferences.edit(); + editor.putBoolean(Helper.SHOW_BATTERY_SAVER_MESSAGE, false); + editor.apply(); + warning_battery_message.setVisibility(View.GONE); + return true; + } + } + return false; + } + }); + warning_battery_message.setOnClickListener(new View.OnClickListener() { + @SuppressLint("BatteryLife") + @Override + public void onClick(View v) { + try { + Intent battSaverIntent = new Intent(); + battSaverIntent.setComponent(new ComponentName("com.android.settings", "com.android.settings.Settings$BatterySaverSettingsActivity")); + startActivityForResult(battSaverIntent, 0); + } catch (ActivityNotFoundException e) { + try { + Intent batterySaverIntent; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP_MR1) { + batterySaverIntent = new Intent(Settings.ACTION_BATTERY_SAVER_SETTINGS); + startActivity(batterySaverIntent); + } + } catch (ActivityNotFoundException ignored) { + } } } - return false; - } - }); - warning_battery_message.setOnClickListener(new View.OnClickListener() { - @SuppressLint("BatteryLife") - @Override - public void onClick(View v) { - try { - Intent battSaverIntent = new Intent(); - battSaverIntent.setComponent(new ComponentName("com.android.settings", "com.android.settings.Settings$BatterySaverSettingsActivity")); - startActivityForResult(battSaverIntent, 0); - }catch (ActivityNotFoundException e){ - try { - Intent batterySaverIntent; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP_MR1) { - batterySaverIntent = new Intent(Settings.ACTION_BATTERY_SAVER_SETTINGS); - startActivity(batterySaverIntent); - } - }catch (ActivityNotFoundException ignored){} - } - } - }); - }else { - warning_battery_message.setVisibility(View.GONE); + }); + } else { + warning_battery_message.setVisibility(View.GONE); + } } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6ab93c3ac..cf7b04be3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -833,6 +833,7 @@ From server Toots (Server) Toots (Device) + Modify