Add emoji reactions for Pleroma

This commit is contained in:
Thomas 2022-07-19 15:49:47 +02:00
parent cf1a1b3e53
commit 8a0460536c
14 changed files with 378 additions and 76 deletions

View file

@ -855,7 +855,7 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
binding.toolbarSearch.setOnSearchClickListener(v -> binding.tabLayout.setVisibility(View.VISIBLE)); binding.toolbarSearch.setOnSearchClickListener(v -> binding.tabLayout.setVisibility(View.VISIBLE));
//For receiving data from other activities //For receiving data from other activities
LocalBroadcastManager.getInstance(BaseMainActivity.this).registerReceiver(broadcast_data, new IntentFilter(Helper.BROADCAST_DATA)); LocalBroadcastManager.getInstance(BaseMainActivity.this).registerReceiver(broadcast_data, new IntentFilter(Helper.BROADCAST_DATA));
if (emojis == null || !emojis.containsKey(BaseMainActivity.currentInstance)) { if (emojis == null || !emojis.containsKey(BaseMainActivity.currentInstance) || emojis.get(BaseMainActivity.currentInstance) == null) {
new Thread(() -> { new Thread(() -> {
try { try {
emojis.put(currentInstance, new EmojiInstance(BaseMainActivity.this).getEmojiList(BaseMainActivity.currentInstance)); emojis.put(currentInstance, new EmojiInstance(BaseMainActivity.this).getEmojiList(BaseMainActivity.currentInstance));

View file

@ -0,0 +1,40 @@
package app.fedilab.android.client.endpoints;
/* 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 retrofit2.Call;
import retrofit2.http.DELETE;
import retrofit2.http.Header;
import retrofit2.http.PUT;
import retrofit2.http.Path;
public interface PleromaAPI {
@PUT("pleroma/statuses/{id}/reactions/{name}")
Call<Void> addReaction(
@Header("Authorization") String app_token,
@Path("id") String id,
@Path("name") String name
);
@DELETE("pleroma/statuses/{id}/reactions/{name}")
Call<Void> removeReaction(
@Header("Authorization") String app_token,
@Path("id") String id,
@Path("name") String name
);
}

View file

@ -0,0 +1,25 @@
package app.fedilab.android.client.entities.api;
/* 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 com.google.gson.annotations.SerializedName;
import java.io.Serializable;
import java.util.List;
public class Pleroma implements Serializable {
@SerializedName("emoji_reactions")
public List<Reaction> emoji_reactions;
}

View file

@ -16,7 +16,9 @@ package app.fedilab.android.client.entities.api;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
public class Reaction { import java.io.Serializable;
public class Reaction implements Serializable {
@SerializedName("name") @SerializedName("name")
public String name; public String name;
@SerializedName("count") @SerializedName("count")

View file

@ -89,6 +89,8 @@ public class Status implements Serializable, Cloneable {
public Card card; public Card card;
@SerializedName("poll") @SerializedName("poll")
public Poll poll; public Poll poll;
@SerializedName("pleroma")
public Pleroma pleroma;
public Attachment art_attachment; public Attachment art_attachment;

View file

@ -76,17 +76,18 @@ public class AnnouncementAdapter extends RecyclerView.Adapter<AnnouncementAdapte
return new AnnouncementHolder(itemBinding); return new AnnouncementHolder(itemBinding);
} }
@Override @Override
public void onBindViewHolder(@NonNull AnnouncementHolder holder, int position) { public void onBindViewHolder(@NonNull AnnouncementHolder holder, int position) {
Announcement announcement = announcements.get(position); Announcement announcement = announcements.get(position);
if (announcement.reactions != null && announcement.reactions.size() > 0) { if (announcement.reactions != null && announcement.reactions.size() > 0) {
ReactionAdapter reactionAdapter = new ReactionAdapter(announcement.id, announcement.reactions); ReactionAdapter reactionAdapter = new ReactionAdapter(announcement.id, announcement.reactions);
holder.binding.reactionsView.setAdapter(reactionAdapter); holder.binding.layoutReactions.reactionsView.setAdapter(reactionAdapter);
LinearLayoutManager layoutManager LinearLayoutManager layoutManager
= new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false); = new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false);
holder.binding.reactionsView.setLayoutManager(layoutManager); holder.binding.layoutReactions.reactionsView.setLayoutManager(layoutManager);
} else { } else {
holder.binding.reactionsView.setAdapter(null); holder.binding.layoutReactions.reactionsView.setAdapter(null);
} }
holder.binding.content.setText( holder.binding.content.setText(
announcement.getSpanContent(context, announcement.getSpanContent(context,
@ -108,11 +109,11 @@ public class AnnouncementAdapter extends RecyclerView.Adapter<AnnouncementAdapte
} else { } else {
holder.binding.dates.setVisibility(View.GONE); holder.binding.dates.setVisibility(View.GONE);
} }
holder.binding.statusEmoji.setOnClickListener(v -> { holder.binding.layoutReactions.statusEmoji.setOnClickListener(v -> {
EmojiManager.install(new EmojiOneProvider()); EmojiManager.install(new EmojiOneProvider());
final EmojiPopup emojiPopup = EmojiPopup.Builder.fromRootView(holder.binding.statusEmoji).setOnEmojiPopupDismissListener(() -> { final EmojiPopup emojiPopup = EmojiPopup.Builder.fromRootView(holder.binding.layoutReactions.statusEmoji).setOnEmojiPopupDismissListener(() -> {
InputMethodManager imm = (InputMethodManager) context.getSystemService(INPUT_METHOD_SERVICE); InputMethodManager imm = (InputMethodManager) context.getSystemService(INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(holder.binding.statusEmoji.getWindowToken(), 0); imm.hideSoftInputFromWindow(holder.binding.layoutReactions.statusEmoji.getWindowToken(), 0);
}).setOnEmojiClickListener((emoji, imageView) -> { }).setOnEmojiClickListener((emoji, imageView) -> {
String emojiStr = imageView.getUnicode(); String emojiStr = imageView.getUnicode();
boolean alreadyAdded = false; boolean alreadyAdded = false;
@ -142,10 +143,10 @@ public class AnnouncementAdapter extends RecyclerView.Adapter<AnnouncementAdapte
announcementsVM.addReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, announcement.id, emojiStr); announcementsVM.addReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, announcement.id, emojiStr);
} }
}) })
.build(holder.binding.fakeEdittext); .build(holder.binding.layoutReactions.fakeEdittext);
emojiPopup.toggle(); emojiPopup.toggle();
}); });
holder.binding.statusAddCustomEmoji.setOnClickListener(v -> { holder.binding.layoutReactions.statusAddCustomEmoji.setOnClickListener(v -> {
final AlertDialog.Builder builder = new AlertDialog.Builder(context, Helper.dialogStyle()); final AlertDialog.Builder builder = new AlertDialog.Builder(context, Helper.dialogStyle());
int paddingPixel = 15; int paddingPixel = 15;
float density = context.getResources().getDisplayMetrics().density; float density = context.getResources().getDisplayMetrics().density;

View file

@ -42,7 +42,7 @@ public class EmojiAdapter extends BaseAdapter {
} }
public int getCount() { public int getCount() {
return emojiList.size(); return emojiList == null ? 0 : emojiList.size();
} }
public Emoji getItem(int position) { public Emoji getItem(int position) {

View file

@ -15,6 +15,8 @@ package app.fedilab.android.ui.drawer;
* see <http://www.gnu.org/licenses>. */ * see <http://www.gnu.org/licenses>. */
import static android.content.Context.INPUT_METHOD_SERVICE;
import static app.fedilab.android.BaseMainActivity.emojis;
import static app.fedilab.android.BaseMainActivity.regex_home; import static app.fedilab.android.BaseMainActivity.regex_home;
import static app.fedilab.android.BaseMainActivity.regex_local; import static app.fedilab.android.BaseMainActivity.regex_local;
import static app.fedilab.android.BaseMainActivity.regex_public; import static app.fedilab.android.BaseMainActivity.regex_public;
@ -46,7 +48,9 @@ import android.view.LayoutInflater;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.GridView;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.RadioButton; import android.widget.RadioButton;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
@ -66,6 +70,7 @@ import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelStoreOwner; import androidx.lifecycle.ViewModelStoreOwner;
import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide; import com.bumptech.glide.Glide;
@ -78,6 +83,9 @@ import com.github.stom79.mytransl.client.HttpsConnectionException;
import com.github.stom79.mytransl.client.Results; import com.github.stom79.mytransl.client.Results;
import com.github.stom79.mytransl.translate.Params; import com.github.stom79.mytransl.translate.Params;
import com.github.stom79.mytransl.translate.Translate; import com.github.stom79.mytransl.translate.Translate;
import com.vanniktech.emoji.EmojiManager;
import com.vanniktech.emoji.EmojiPopup;
import com.vanniktech.emoji.one.EmojiOneProvider;
import com.varunest.sparkbutton.SparkButton; import com.varunest.sparkbutton.SparkButton;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
@ -93,6 +101,7 @@ import app.fedilab.android.R;
import app.fedilab.android.activities.ComposeActivity; import app.fedilab.android.activities.ComposeActivity;
import app.fedilab.android.activities.ContextActivity; import app.fedilab.android.activities.ContextActivity;
import app.fedilab.android.activities.CustomSharingActivity; import app.fedilab.android.activities.CustomSharingActivity;
import app.fedilab.android.activities.MainActivity;
import app.fedilab.android.activities.MediaActivity; import app.fedilab.android.activities.MediaActivity;
import app.fedilab.android.activities.ProfileActivity; import app.fedilab.android.activities.ProfileActivity;
import app.fedilab.android.activities.ReportActivity; import app.fedilab.android.activities.ReportActivity;
@ -100,7 +109,9 @@ import app.fedilab.android.activities.StatusInfoActivity;
import app.fedilab.android.client.entities.api.Attachment; import app.fedilab.android.client.entities.api.Attachment;
import app.fedilab.android.client.entities.api.Notification; import app.fedilab.android.client.entities.api.Notification;
import app.fedilab.android.client.entities.api.Poll; import app.fedilab.android.client.entities.api.Poll;
import app.fedilab.android.client.entities.api.Reaction;
import app.fedilab.android.client.entities.api.Status; import app.fedilab.android.client.entities.api.Status;
import app.fedilab.android.client.entities.app.Account;
import app.fedilab.android.client.entities.app.StatusCache; import app.fedilab.android.client.entities.app.StatusCache;
import app.fedilab.android.client.entities.app.StatusDraft; import app.fedilab.android.client.entities.app.StatusDraft;
import app.fedilab.android.client.entities.app.Timeline; import app.fedilab.android.client.entities.app.Timeline;
@ -124,6 +135,7 @@ import app.fedilab.android.ui.fragment.timeline.FragmentMastodonContext;
import app.fedilab.android.viewmodel.mastodon.AccountsVM; import app.fedilab.android.viewmodel.mastodon.AccountsVM;
import app.fedilab.android.viewmodel.mastodon.SearchVM; import app.fedilab.android.viewmodel.mastodon.SearchVM;
import app.fedilab.android.viewmodel.mastodon.StatusesVM; import app.fedilab.android.viewmodel.mastodon.StatusesVM;
import app.fedilab.android.viewmodel.pleroma.ActionsVM;
import es.dmoral.toasty.Toasty; import es.dmoral.toasty.Toasty;
import jp.wasabeef.glide.transformations.BlurTransformation; import jp.wasabeef.glide.transformations.BlurTransformation;
@ -313,6 +325,116 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
boolean fullAttachement = sharedpreferences.getBoolean(context.getString(R.string.SET_FULL_PREVIEW), false); boolean fullAttachement = sharedpreferences.getBoolean(context.getString(R.string.SET_FULL_PREVIEW), false);
boolean displayBookmark = sharedpreferences.getBoolean(context.getString(R.string.SET_DISPLAY_BOOKMARK), false); boolean displayBookmark = sharedpreferences.getBoolean(context.getString(R.string.SET_DISPLAY_BOOKMARK), false);
if (MainActivity.currentAccount != null && MainActivity.currentAccount.api == Account.API.PLEROMA) {
holder.binding.layoutReactions.getRoot().setVisibility(View.VISIBLE);
if (status.pleroma != null && status.pleroma.emoji_reactions != null && status.pleroma.emoji_reactions.size() > 0) {
ReactionAdapter reactionAdapter = new ReactionAdapter(status.id, status.pleroma.emoji_reactions);
holder.binding.layoutReactions.reactionsView.setAdapter(reactionAdapter);
LinearLayoutManager layoutManager
= new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false);
holder.binding.layoutReactions.reactionsView.setLayoutManager(layoutManager);
} else {
holder.binding.layoutReactions.reactionsView.setAdapter(null);
}
holder.binding.layoutReactions.statusEmoji.setOnClickListener(v -> {
EmojiManager.install(new EmojiOneProvider());
final EmojiPopup emojiPopup = EmojiPopup.Builder.fromRootView(holder.binding.layoutReactions.statusEmoji).setOnEmojiPopupDismissListener(() -> {
InputMethodManager imm = (InputMethodManager) context.getSystemService(INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(holder.binding.layoutReactions.statusEmoji.getWindowToken(), 0);
}).setOnEmojiClickListener((emoji, imageView) -> {
String emojiStr = imageView.getUnicode();
boolean alreadyAdded = false;
for (Reaction reaction : status.pleroma.emoji_reactions) {
if (reaction.name.compareTo(emojiStr) == 0) {
alreadyAdded = true;
reaction.count = (reaction.count - 1);
if (reaction.count == 0) {
status.pleroma.emoji_reactions.remove(reaction);
}
adapter.notifyItemChanged(getPositionAsync(notificationList, statusList, statusToDeal));
break;
}
}
if (!alreadyAdded) {
Reaction reaction = new Reaction();
reaction.me = true;
reaction.count = 1;
reaction.name = emojiStr;
status.pleroma.emoji_reactions.add(0, reaction);
adapter.notifyItemChanged(getPositionAsync(notificationList, statusList, statusToDeal));
}
ActionsVM actionVM = new ViewModelProvider((ViewModelStoreOwner) context).get(ActionsVM.class);
if (alreadyAdded) {
actionVM.removeReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr);
} else {
actionVM.addReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr);
}
})
.build(holder.binding.layoutReactions.fakeEdittext);
emojiPopup.toggle();
});
holder.binding.layoutReactions.statusAddCustomEmoji.setOnClickListener(v -> {
final AlertDialog.Builder builder = new AlertDialog.Builder(context, Helper.dialogStyle());
int paddingPixel = 15;
float density = context.getResources().getDisplayMetrics().density;
int paddingDp = (int) (paddingPixel * density);
builder.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
builder.setTitle(R.string.insert_emoji);
AlertDialog alertDialogEmoji = null;
if (emojis != null && emojis.size() > 0 && emojis.get(BaseMainActivity.currentInstance) != null) {
GridView gridView = new GridView(context);
gridView.setAdapter(new EmojiAdapter(emojis.get(BaseMainActivity.currentInstance)));
gridView.setNumColumns(5);
AlertDialog finalAlertDialogEmoji = alertDialogEmoji;
gridView.setOnItemClickListener((parent, view, index, id) -> {
String emojiStr = emojis.get(BaseMainActivity.currentInstance).get(index).shortcode;
String url = emojis.get(BaseMainActivity.currentInstance).get(index).url;
String static_url = emojis.get(BaseMainActivity.currentInstance).get(index).static_url;
boolean alreadyAdded = false;
for (Reaction reaction : status.pleroma.emoji_reactions) {
if (reaction.name.compareTo(emojiStr) == 0) {
alreadyAdded = true;
reaction.count = (reaction.count - 1);
if (reaction.count == 0) {
status.pleroma.emoji_reactions.remove(reaction);
}
adapter.notifyItemChanged(getPositionAsync(notificationList, statusList, statusToDeal));
break;
}
}
if (!alreadyAdded) {
Reaction reaction = new Reaction();
reaction.me = true;
reaction.count = 1;
reaction.name = emojiStr;
reaction.url = url;
reaction.static_url = static_url;
status.pleroma.emoji_reactions.add(0, reaction);
adapter.notifyItemChanged(getPositionAsync(notificationList, statusList, statusToDeal));
}
ActionsVM actionsVM = new ViewModelProvider((ViewModelStoreOwner) context).get(ActionsVM.class);
if (alreadyAdded) {
actionsVM.removeReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr);
} else {
actionsVM.addReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr);
}
if (finalAlertDialogEmoji != null) {
finalAlertDialogEmoji.dismiss();
}
});
gridView.setPadding(paddingDp, paddingDp, paddingDp, paddingDp);
builder.setView(gridView);
} else {
TextView textView = new TextView(context);
textView.setText(context.getString(R.string.no_emoji));
textView.setPadding(paddingDp, paddingDp, paddingDp, paddingDp);
builder.setView(textView);
}
alertDialogEmoji = builder.show();
});
}
int truncate_toots_size = sharedpreferences.getInt(context.getString(R.string.SET_TRUNCATE_TOOTS_SIZE), 0); int truncate_toots_size = sharedpreferences.getInt(context.getString(R.string.SET_TRUNCATE_TOOTS_SIZE), 0);
// boolean display_video_preview = sharedpreferences.getBoolean(context.getString(R.string.SET_DISPLAY_VIDEO_PREVIEWS), true); // boolean display_video_preview = sharedpreferences.getBoolean(context.getString(R.string.SET_DISPLAY_VIDEO_PREVIEWS), true);
// boolean isModerator = sharedpreferences.getBoolean(Helper.PREF_IS_MODERATOR, false); // boolean isModerator = sharedpreferences.getBoolean(Helper.PREF_IS_MODERATOR, false);

View file

@ -174,10 +174,12 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
} }
public void scrollToTop() { public void scrollToTop() {
if (binding != null) {
binding.swipeContainer.setRefreshing(true); binding.swipeContainer.setRefreshing(true);
flagLoading = false; flagLoading = false;
route(DIRECTION.SCROLL_TOP, true); route(DIRECTION.SCROLL_TOP, true);
} }
}
public View onCreateView(@NonNull LayoutInflater inflater, public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) { ViewGroup container, Bundle savedInstanceState) {

View file

@ -23,9 +23,6 @@ import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -54,7 +51,6 @@ public class AnnouncementsVM extends AndroidViewModel {
} }
private MastodonAnnouncementsService init(@NonNull String instance) { private MastodonAnnouncementsService init(@NonNull String instance) {
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").create();
Retrofit retrofit = new Retrofit.Builder() Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://" + instance + "/api/v1/") .baseUrl("https://" + instance + "/api/v1/")
.addConverterFactory(GsonConverterFactory.create(Helper.getDateBuilder())) .addConverterFactory(GsonConverterFactory.create(Helper.getDateBuilder()))

View file

@ -0,0 +1,101 @@
package app.fedilab.android.viewmodel.pleroma;
/* 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.app.Application;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.MutableLiveData;
import java.util.List;
import java.util.concurrent.TimeUnit;
import app.fedilab.android.client.endpoints.PleromaAPI;
import app.fedilab.android.client.entities.api.Announcement;
import app.fedilab.android.helper.Helper;
import okhttp3.OkHttpClient;
import retrofit2.Call;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class ActionsVM extends AndroidViewModel {
final OkHttpClient okHttpClient = new OkHttpClient.Builder()
.readTimeout(60, TimeUnit.SECONDS)
.connectTimeout(60, TimeUnit.SECONDS)
.callTimeout(60, TimeUnit.SECONDS)
.proxy(Helper.getProxy(getApplication().getApplicationContext()))
.build();
private MutableLiveData<Announcement> announcementMutableLiveData;
private MutableLiveData<List<Announcement>> announcementListMutableLiveData;
public ActionsVM(@NonNull Application application) {
super(application);
}
private PleromaAPI init(@NonNull String instance) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://" + instance + "/api/v1/")
.addConverterFactory(GsonConverterFactory.create(Helper.getDateBuilder()))
.client(okHttpClient)
.build();
return retrofit.create(PleromaAPI.class);
}
/**
* React to an announcement with an emoji.
*
* @param instance Instance domain of the active account
* @param token Access token of the active account
* @param id Local ID of an announcement
* @param name Unicode emoji, or shortcode of custom emoji
*/
public void addReaction(@NonNull String instance, String token, @NonNull String id, @NonNull String name) {
PleromaAPI pleromaAPI = init(instance);
new Thread(() -> {
Call<Void> addReactionCall = pleromaAPI.addReaction(token, id, name);
if (addReactionCall != null) {
try {
addReactionCall.execute();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
/**
* Undo a react emoji to an announcement.
*
* @param instance Instance domain of the active account
* @param token Access token of the active account
* @param id Local ID of an announcement
* @param name Unicode emoji, or shortcode of custom emoji
*/
public void removeReaction(@NonNull String instance, String token, @NonNull String id, @NonNull String name) {
PleromaAPI pleromaAPI = init(instance);
new Thread(() -> {
Call<Void> removeReactionCall = pleromaAPI.removeReaction(token, id, name);
if (removeReactionCall != null) {
try {
removeReactionCall.execute();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}

View file

@ -59,64 +59,9 @@
tools:maxLines="10" tools:maxLines="10"
tools:text="@tools:sample/lorem/random" /> tools:text="@tools:sample/lorem/random" />
<androidx.appcompat.widget.LinearLayoutCompat <include
android:id="@+id/status_reactions" android:id="@+id/layout_reactions"
android:layout_width="match_parent" layout="@layout/layout_reactions" />
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:paddingBottom="10dp"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/content">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/reactions_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/status_add_custom_emoji"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="5dp"
android:contentDescription="@string/add_reaction"
android:src="@drawable/ic_baseline_emoji_emotions_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:tint="?attr/iconColor" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/status_emoji"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="5dp"
android:contentDescription="@string/add_reaction"
android:src="@drawable/ic_baseline_add_reaction_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:tint="?attr/iconColor" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone">
<app.fedilab.android.helper.FedilabAutoCompleteTextView
android:id="@+id/fake_edittext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:importantForAutofill="noExcludeDescendants"
android:inputType="text" />
</LinearLayout>
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView> </com.google.android.material.card.MaterialCardView>

View file

@ -601,6 +601,12 @@
</androidx.appcompat.widget.LinearLayoutCompat> </androidx.appcompat.widget.LinearLayoutCompat>
<include
android:id="@+id/layout_reactions"
layout="@layout/layout_reactions"
android:visibility="gone"
tools:visibility="visible" />
</androidx.appcompat.widget.LinearLayoutCompat> </androidx.appcompat.widget.LinearLayoutCompat>
</com.google.android.material.card.MaterialCardView> </com.google.android.material.card.MaterialCardView>

View file

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/status_reactions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:orientation="horizontal"
android:paddingBottom="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/content">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/reactions_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/status_add_custom_emoji"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="5dp"
android:contentDescription="@string/add_reaction"
android:src="@drawable/ic_baseline_emoji_emotions_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:tint="?attr/iconColor" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/status_emoji"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="5dp"
android:contentDescription="@string/add_reaction"
android:src="@drawable/ic_baseline_add_reaction_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:tint="?attr/iconColor" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone">
<app.fedilab.android.helper.FedilabAutoCompleteTextView
android:id="@+id/fake_edittext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:importantForAutofill="noExcludeDescendants"
android:inputType="text" />
</LinearLayout>
</androidx.appcompat.widget.LinearLayoutCompat>