From 13a1a2a7a47cbe93c929d28fe793ae244e41c311 Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 1 Nov 2022 11:15:13 +0100 Subject: [PATCH] Message history --- app/src/main/AndroidManifest.xml | 5 + .../activities/StatusHistoryActivity.java | 85 +++++++++++++ .../endpoints/MastodonStatusesService.java | 5 + .../android/client/entities/app/Timeline.java | 2 + .../android/ui/drawer/StatusAdapter.java | 6 + .../ui/drawer/StatusHistoryAdapter.java | 112 ++++++++++++++++++ .../viewmodel/mastodon/StatusesVM.java | 33 ++++++ .../res/layout/activity_status_history.xml | 45 +++++++ .../main/res/layout/drawer_status_history.xml | 103 ++++++++++++++++ app/src/main/res/values/strings.xml | 3 + 10 files changed, 399 insertions(+) create mode 100644 app/src/main/java/app/fedilab/android/activities/StatusHistoryActivity.java create mode 100644 app/src/main/java/app/fedilab/android/ui/drawer/StatusHistoryAdapter.java create mode 100644 app/src/main/res/layout/activity_status_history.xml create mode 100644 app/src/main/res/layout/drawer_status_history.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 30591a71..4423618e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -156,6 +156,11 @@ + diff --git a/app/src/main/java/app/fedilab/android/activities/StatusHistoryActivity.java b/app/src/main/java/app/fedilab/android/activities/StatusHistoryActivity.java new file mode 100644 index 00000000..24a9c6b7 --- /dev/null +++ b/app/src/main/java/app/fedilab/android/activities/StatusHistoryActivity.java @@ -0,0 +1,85 @@ +package app.fedilab.android.activities; +/* Copyright 2022 Thomas Schneider + * + * This file is a part of Fedilab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Fedilab; if not, + * see . */ + + +import android.content.res.Resources; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.view.MenuItem; + +import androidx.core.content.ContextCompat; +import androidx.lifecycle.ViewModelProvider; +import androidx.recyclerview.widget.LinearLayoutManager; + +import app.fedilab.android.R; +import app.fedilab.android.databinding.ActivityStatusHistoryBinding; +import app.fedilab.android.helper.Helper; +import app.fedilab.android.helper.ThemeHelper; +import app.fedilab.android.ui.drawer.StatusHistoryAdapter; +import app.fedilab.android.viewmodel.mastodon.StatusesVM; +import es.dmoral.toasty.Toasty; + + +public class StatusHistoryActivity extends BaseActivity { + + public static Resources.Theme theme; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ThemeHelper.applyTheme(this); + ActivityStatusHistoryBinding binding = ActivityStatusHistoryBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); + + + if (getSupportActionBar() != null) { + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary))); + } + + Bundle b = getIntent().getExtras(); + String statusId; + if (b != null) { + statusId = b.getString(Helper.ARG_STATUS_ID); + } else { + finish(); + return; + } + StatusesVM statusesVM = new ViewModelProvider(StatusHistoryActivity.this).get(StatusesVM.class); + statusesVM.getStatusHistory(MainActivity.currentInstance, MainActivity.currentToken, statusId).observe(this, statuses -> { + if (statuses != null && statuses.size() > 0) { + StatusHistoryAdapter statusHistoryAdapter = new StatusHistoryAdapter(statuses); + binding.recyclerView.setAdapter(statusHistoryAdapter); + binding.recyclerView.setLayoutManager(new LinearLayoutManager(this)); + } else { + Toasty.error(this, getString(R.string.toast_error), Toasty.LENGTH_LONG).show(); + finish(); + } + }); + + } + + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + finish(); + return true; + } + return true; + } + +} \ No newline at end of file diff --git a/app/src/main/java/app/fedilab/android/client/endpoints/MastodonStatusesService.java b/app/src/main/java/app/fedilab/android/client/endpoints/MastodonStatusesService.java index 12320f0f..08ae1d50 100644 --- a/app/src/main/java/app/fedilab/android/client/endpoints/MastodonStatusesService.java +++ b/app/src/main/java/app/fedilab/android/client/endpoints/MastodonStatusesService.java @@ -67,6 +67,11 @@ public interface MastodonStatusesService { @Header("Authorization") String token, @Path("id") String id); + @GET("statuses/{id}/history") + Call> getStatusHistory( + @Header("Authorization") String token, + @Path("id") String id); + //Post a status @FormUrlEncoded @PUT("statuses/{id}") diff --git a/app/src/main/java/app/fedilab/android/client/entities/app/Timeline.java b/app/src/main/java/app/fedilab/android/client/entities/app/Timeline.java index 100455e5..a02a60ae 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/app/Timeline.java +++ b/app/src/main/java/app/fedilab/android/client/entities/app/Timeline.java @@ -378,6 +378,8 @@ public class Timeline { TREND_TAG("TREND_TAG"), @SerializedName("TREND_MESSAGE") TREND_MESSAGE("TREND_MESSAGE"), + @SerializedName("STATUS_HISTORY") + STATUS_HISTORY("STATUS_HISTORY"), @SerializedName("ACCOUNT_TIMELINE") ACCOUNT_TIMELINE("ACCOUNT_TIMELINE"), @SerializedName("MUTED_TIMELINE") diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java index 45bff2dd..b2104e33 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java @@ -104,6 +104,7 @@ import app.fedilab.android.activities.MainActivity; import app.fedilab.android.activities.MediaActivity; import app.fedilab.android.activities.ProfileActivity; import app.fedilab.android.activities.ReportActivity; +import app.fedilab.android.activities.StatusHistoryActivity; import app.fedilab.android.activities.StatusInfoActivity; import app.fedilab.android.client.entities.api.Attachment; import app.fedilab.android.client.entities.api.Poll; @@ -983,6 +984,11 @@ public class StatusAdapter extends RecyclerView.Adapter if (statusToDeal.edited_at != null) { holder.binding.time.setText(context.getString(R.string.full_date_edited, Helper.longDateToString(status.created_at), Helper.longDateToString(status.edited_at))); + holder.binding.time.setOnClickListener(v -> { + Intent historyIntent = new Intent(context, StatusHistoryActivity.class); + historyIntent.putExtra(Helper.ARG_STATUS_ID, statusToDeal.id); + context.startActivity(historyIntent); + }); } else { holder.binding.time.setText(Helper.longDateToString(status.created_at)); } diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/StatusHistoryAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/StatusHistoryAdapter.java new file mode 100644 index 00000000..774185dc --- /dev/null +++ b/app/src/main/java/app/fedilab/android/ui/drawer/StatusHistoryAdapter.java @@ -0,0 +1,112 @@ +package app.fedilab.android.ui.drawer; +/* Copyright 2022 Thomas Schneider + * + * This file is a part of Fedilab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Fedilab; if not, + * see . */ + +import android.content.Context; +import android.content.SharedPreferences; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; +import androidx.preference.PreferenceManager; +import androidx.recyclerview.widget.RecyclerView; + +import java.lang.ref.WeakReference; +import java.util.List; + +import app.fedilab.android.R; +import app.fedilab.android.client.entities.api.Status; +import app.fedilab.android.databinding.DrawerStatusHistoryBinding; +import app.fedilab.android.helper.Helper; +import app.fedilab.android.helper.MastodonHelper; + + +public class StatusHistoryAdapter extends RecyclerView.Adapter { + + private final List statuses; + private Context context; + + public StatusHistoryAdapter(List statusList) { + statuses = statusList; + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + context = parent.getContext(); + DrawerStatusHistoryBinding itemBinding = DrawerStatusHistoryBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); + return new StatusHistoryViewHolder(itemBinding); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) { + StatusHistoryViewHolder holder = (StatusHistoryViewHolder) viewHolder; + Status status = statuses.get(position); + holder.binding.statusContent.setText( + status.getSpanContent(context, + new WeakReference<>(holder.binding.statusContent)), + TextView.BufferType.SPANNABLE); + if (status.spoiler_text != null && !status.spoiler_text.trim().isEmpty()) { + holder.binding.spoiler.setVisibility(View.VISIBLE); + holder.binding.spoiler.setText( + status.getSpanSpoiler(context, + new WeakReference<>(holder.binding.spoiler)), + TextView.BufferType.SPANNABLE); + } else { + holder.binding.spoiler.setVisibility(View.GONE); + holder.binding.spoiler.setText(null); + } + MastodonHelper.loadPPMastodon(holder.binding.avatar, status.account); + if (status.account != null) { + holder.binding.displayName.setText( + status.account.getSpanDisplayName(context, + new WeakReference<>(holder.binding.displayName)), + TextView.BufferType.SPANNABLE); + holder.binding.username.setText(String.format("@%s", status.account.acct)); + } + int theme_statuses_color = -1; + SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context); + if (sharedpreferences.getBoolean("use_custom_theme", false)) { + theme_statuses_color = sharedpreferences.getInt("theme_statuses_color", -1); + } + if (theme_statuses_color != -1) { + holder.binding.cardviewContainer.setBackgroundColor(theme_statuses_color); + } else { + holder.binding.cardviewContainer.setBackgroundColor(ContextCompat.getColor(context, R.color.cyanea_primary_dark_reference)); + } + if (position == 0) { + holder.binding.dateModif.setText(context.getString(R.string.created_message_at, Helper.dateDiffFull(status.created_at))); + } else { + holder.binding.dateModif.setText(context.getString(R.string.edited_message_at, Helper.dateDiffFull(status.created_at))); + } + } + + @Override + public int getItemCount() { + return statuses.size(); + } + + public static class StatusHistoryViewHolder extends RecyclerView.ViewHolder { + DrawerStatusHistoryBinding binding; + + StatusHistoryViewHolder(DrawerStatusHistoryBinding itemView) { + super(itemView.getRoot()); + binding = itemView; + } + } +} diff --git a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/StatusesVM.java b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/StatusesVM.java index e0c032c4..be870a9f 100644 --- a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/StatusesVM.java +++ b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/StatusesVM.java @@ -64,6 +64,7 @@ public class StatusesVM extends AndroidViewModel { private MutableLiveData statusMutableLiveData; + private MutableLiveData> statusListMutableLiveData; private MutableLiveData statusSourceMutableLiveData; private MutableLiveData scheduledStatusMutableLiveData; private MutableLiveData scheduledStatusesMutableLiveData; @@ -333,6 +334,38 @@ public class StatusesVM extends AndroidViewModel { return statusSourceMutableLiveData; } + /** + * Get a history of statuses by id + * + * @param instance Instance domain of the active account + * @param token Access token of the active account + * @param id String - id of the status + * @return LiveData + */ + public LiveData> getStatusHistory(@NonNull String instance, String token, String id) { + MastodonStatusesService mastodonStatusesService = init(instance); + statusListMutableLiveData = new MutableLiveData<>(); + new Thread(() -> { + Call> statusListCall = mastodonStatusesService.getStatusHistory(token, id); + List statusList = null; + if (statusListCall != null) { + try { + Response> statusResponse = statusListCall.execute(); + if (statusResponse.isSuccessful()) { + statusList = statusResponse.body(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + Handler mainHandler = new Handler(Looper.getMainLooper()); + List finalStatusList = statusList; + Runnable myRunnable = () -> statusListMutableLiveData.setValue(finalStatusList); + mainHandler.post(myRunnable); + }).start(); + return statusListMutableLiveData; + } + /** * Delete a status by ID * diff --git a/app/src/main/res/layout/activity_status_history.xml b/app/src/main/res/layout/activity_status_history.xml new file mode 100644 index 00000000..044814fa --- /dev/null +++ b/app/src/main/res/layout/activity_status_history.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/drawer_status_history.xml b/app/src/main/res/layout/drawer_status_history.xml new file mode 100644 index 00000000..5a0d8d7e --- /dev/null +++ b/app/src/main/res/layout/drawer_status_history.xml @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 95fc8d4b..937f6d8e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1557,4 +1557,7 @@ Force translation to a specific language. Choose first value to reset to device settings Edit message %1$s edited %2$s + Message history + Edited at %1$s + Created at %1$s