Message history

This commit is contained in:
Thomas 2022-11-01 11:15:13 +01:00
parent 0189dad4d3
commit 13a1a2a7a4
10 changed files with 399 additions and 0 deletions

View file

@ -156,6 +156,11 @@
<activity
android:name=".activities.WebviewConnectActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".activities.StatusHistoryActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/status_history"
android:theme="@style/AppThemeBar" />
<activity
android:name=".activities.ContextActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />

View file

@ -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 <http://www.gnu.org/licenses>. */
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;
}
}

View file

@ -67,6 +67,11 @@ public interface MastodonStatusesService {
@Header("Authorization") String token,
@Path("id") String id);
@GET("statuses/{id}/history")
Call<List<Status>> getStatusHistory(
@Header("Authorization") String token,
@Path("id") String id);
//Post a status
@FormUrlEncoded
@PUT("statuses/{id}")

View file

@ -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")

View file

@ -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<RecyclerView.ViewHolder>
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));
}

View file

@ -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 <http://www.gnu.org/licenses>. */
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<RecyclerView.ViewHolder> {
private final List<Status> statuses;
private Context context;
public StatusHistoryAdapter(List<Status> 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;
}
}
}

View file

@ -64,6 +64,7 @@ public class StatusesVM extends AndroidViewModel {
private MutableLiveData<Status> statusMutableLiveData;
private MutableLiveData<List<Status>> statusListMutableLiveData;
private MutableLiveData<StatusSource> statusSourceMutableLiveData;
private MutableLiveData<ScheduledStatus> scheduledStatusMutableLiveData;
private MutableLiveData<ScheduledStatuses> 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<Status>
*/
public LiveData<List<Status>> getStatusHistory(@NonNull String instance, String token, String id) {
MastodonStatusesService mastodonStatusesService = init(instance);
statusListMutableLiveData = new MutableLiveData<>();
new Thread(() -> {
Call<List<Status>> statusListCall = mastodonStatusesService.getStatusHistory(token, id);
List<Status> statusList = null;
if (statusListCall != null) {
try {
Response<List<Status>> statusResponse = statusListCall.execute();
if (statusResponse.isSuccessful()) {
statusList = statusResponse.body();
}
} catch (Exception e) {
e.printStackTrace();
}
}
Handler mainHandler = new Handler(Looper.getMainLooper());
List<Status> finalStatusList = statusList;
Runnable myRunnable = () -> statusListMutableLiveData.setValue(finalStatusList);
mainHandler.post(myRunnable);
}).start();
return statusListMutableLiveData;
}
/**
* Delete a status by ID
*

View file

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?><!--
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 <http://www.gnu.org/licenses>.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:scrollbars="none" />
<!-- Main Loader -->
<RelativeLayout
android:id="@+id/loader"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:visibility="gone">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true"
android:indeterminateTint="@color/cyanea_accent_dark_reference" />
</RelativeLayout>
</RelativeLayout>

View file

@ -0,0 +1,103 @@
<?xml version="1.0" encoding="utf-8"?><!--
Copyright 2021 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 <http://www.gnu.org/licenses>
-->
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/cardview_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="12dp"
android:layout_marginTop="12dp"
android:clipChildren="false"
android:clipToPadding="false"
app:cardElevation="2dp">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="6dp"
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="vertical">
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/status_user_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal"
android:padding="6dp">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/avatar"
android:layout_width="20dp"
android:layout_height="20dp"
android:scaleType="centerInside"
tools:src="@drawable/ic_person" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/display_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:ellipsize="end"
android:maxLines="1"
tools:text="Display Name" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:alpha="0.7"
android:ellipsize="end"
android:maxLines="1"
tools:text="\@username\@instance.test" />
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/date_modif"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
tools:text="@tools:sample/date/ddmmyy" />
<com.google.android.material.divider.MaterialDivider
android:layout_width="match_parent"
android:layout_height="1dp" />
<app.fedilab.android.helper.CustomTextView
android:id="@+id/spoiler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="6dp"
android:layout_marginTop="6dp"
tools:text="Warning: Lorem Ipsum below" />
<app.fedilab.android.helper.CustomTextView
android:id="@+id/status_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="6dp"
android:layout_marginTop="6dp"
android:textIsSelectable="true"
tools:maxLines="10"
tools:text="@tools:sample/lorem/random" />
</androidx.appcompat.widget.LinearLayoutCompat>
</com.google.android.material.card.MaterialCardView>

View file

@ -1557,4 +1557,7 @@
<string name="set_live_translate">Force translation to a specific language. Choose first value to reset to device settings</string>
<string name="edit_message">Edit message</string>
<string name="full_date_edited">%1$s edited %2$s</string>
<string name="status_history">Message history</string>
<string name="edited_message_at">Edited at %1$s</string>
<string name="created_message_at">Created at %1$s</string>
</resources>