forked from mirrors/Fedilab
Add emoji reactions for Pleroma
This commit is contained in:
parent
cf1a1b3e53
commit
8a0460536c
14 changed files with 378 additions and 76 deletions
|
@ -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));
|
||||||
|
|
|
@ -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
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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")
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -174,9 +174,11 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
|
||||||
}
|
}
|
||||||
|
|
||||||
public void scrollToTop() {
|
public void scrollToTop() {
|
||||||
binding.swipeContainer.setRefreshing(true);
|
if (binding != null) {
|
||||||
flagLoading = false;
|
binding.swipeContainer.setRefreshing(true);
|
||||||
route(DIRECTION.SCROLL_TOP, true);
|
flagLoading = false;
|
||||||
|
route(DIRECTION.SCROLL_TOP, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||||
|
|
|
@ -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()))
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -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>
|
||||||
|
|
60
app/src/main/res/layout/layout_reactions.xml
Normal file
60
app/src/main/res/layout/layout_reactions.xml
Normal 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>
|
Loading…
Reference in a new issue