package app.fedilab.android.drawers; /* Copyright 2019 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.annotation.SuppressLint; import android.app.Activity; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.database.sqlite.SQLiteDatabase; import android.os.Build; import android.os.Bundle; import android.os.CountDownTimer; import android.text.Html; import android.text.InputType; import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.InputMethodManager; import android.widget.Button; import android.widget.DatePicker; import android.widget.EditText; import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.TimePicker; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.widget.PopupMenu; import androidx.core.app.ActivityOptionsCompat; import androidx.preference.PreferenceManager; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; import com.bumptech.glide.load.resource.bitmap.FitCenter; import com.bumptech.glide.load.resource.bitmap.RoundedCorners; import com.bumptech.glide.request.RequestOptions; import com.github.stom79.mytransl.MyTransL; import com.github.stom79.mytransl.client.HttpsConnectionException; import com.github.stom79.mytransl.client.Results; import com.github.stom79.mytransl.translate.Translate; import com.smarteist.autoimageslider.IndicatorAnimations; import com.smarteist.autoimageslider.SliderAnimations; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.List; import app.fedilab.android.R; import app.fedilab.android.activities.MainActivity; import app.fedilab.android.activities.PixelfedComposeActivity; import app.fedilab.android.activities.ShowAccountActivity; import app.fedilab.android.activities.ShowConversationActivity; import app.fedilab.android.activities.SlideMediaActivity; import app.fedilab.android.activities.TootActivity; import app.fedilab.android.activities.TootInfoActivity; import app.fedilab.android.asynctasks.PostActionAsyncTask; import app.fedilab.android.asynctasks.PostStatusAsyncTask; import app.fedilab.android.asynctasks.RetrieveContextAsyncTask; import app.fedilab.android.asynctasks.RetrieveFeedsAsyncTask; import app.fedilab.android.asynctasks.UpdateAccountInfoAsyncTask; import app.fedilab.android.client.API; import app.fedilab.android.client.APIResponse; import app.fedilab.android.client.Entities.Account; import app.fedilab.android.client.Entities.Emojis; import app.fedilab.android.client.Entities.Error; import app.fedilab.android.client.Entities.Notification; import app.fedilab.android.client.Entities.Status; import app.fedilab.android.client.Entities.StatusDrawerParams; import app.fedilab.android.databinding.DrawerEmptyBinding; import app.fedilab.android.databinding.DrawerPixelfedBinding; import app.fedilab.android.databinding.DrawerPixelfedCommentBinding; import app.fedilab.android.helper.CrossActions; import app.fedilab.android.helper.Helper; import app.fedilab.android.helper.MastalabAutoCompleteTextView; import app.fedilab.android.helper.ThemeHelper; import app.fedilab.android.interfaces.OnPostActionInterface; import app.fedilab.android.interfaces.OnPostStatusActionInterface; import app.fedilab.android.interfaces.OnRetrieveContextInterface; import app.fedilab.android.interfaces.OnRetrieveEmojiInterface; import app.fedilab.android.interfaces.OnRetrieveFeedsInterface; import app.fedilab.android.interfaces.OnRetrieveSearcAccountshInterface; import app.fedilab.android.interfaces.OnRetrieveSearchInterface; import app.fedilab.android.jobs.ScheduledBoostsSyncJob; import app.fedilab.android.sqlite.AccountDAO; import app.fedilab.android.sqlite.Sqlite; import app.fedilab.android.sqlite.StatusCacheDAO; import app.fedilab.android.sqlite.StatusStoredDAO; import app.fedilab.android.sqlite.TempMuteDAO; import es.dmoral.toasty.Toasty; import jp.wasabeef.glide.transformations.BlurTransformation; import static android.content.Context.MODE_PRIVATE; import static app.fedilab.android.activities.BaseMainActivity.mutedAccount; import static app.fedilab.android.activities.BaseMainActivity.social; /** * Created by Thomas on 14/01/2019. * Adapter for pixelfed drawer */ public class PixelfedListAdapter extends RecyclerView.Adapter implements OnPostActionInterface, OnRetrieveEmojiInterface, OnPostStatusActionInterface, OnRetrieveSearchInterface, OnRetrieveSearcAccountshInterface, OnRetrieveContextInterface, OnRetrieveFeedsInterface { private static final int COMMENT_STATUS = 2; private static final int DISPLAYED_STATUS = 1; private final int HIDDEN_STATUS = 0; private final List statuses; private final RetrieveFeedsAsyncTask.Type type; private Context context; private MastalabAutoCompleteTextView comment_content; private String in_reply_to_status; private String visibility; private final boolean redraft; private Status toot; public PixelfedListAdapter(StatusDrawerParams statusDrawerParams) { statuses = statusDrawerParams.getStatuses(); type = statusDrawerParams.getType(); redraft = false; } @Override public long getItemId(int position) { return position; } @Override public int getItemCount() { return statuses.size(); } private Status getItemAt(int position) { if (statuses.size() > position) return statuses.get(position); else return null; } @Override public void onRetrieveContext(APIResponse apiResponse) { if (apiResponse.getError() != null) { return; } List statuses = apiResponse.getContext().getDescendants(); String targetedId = apiResponse.getTargetedId(); int position = 0; for (Status tl : this.statuses) { if (tl.getId().equals(targetedId)) { this.statuses.get(position).setCommentsFetched(true); this.statuses.get(position).setComments(statuses); notifyStatusChanged(this.statuses.get(position)); break; } position++; } } @Override public void onPostStatusAction(APIResponse apiResponse) { if (apiResponse.getError() != null) { if (apiResponse.getError().getError().length() < 100) { Toasty.error(context, apiResponse.getError().getError(), Toast.LENGTH_LONG).show(); } else { Toasty.error(context, context.getString(R.string.long_api_error, "\ud83d\ude05"), Toast.LENGTH_LONG).show(); } return; } final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE); comment_content = null; if (apiResponse.getError() == null) { boolean display_confirm = sharedpreferences.getBoolean(Helper.SET_DISPLAY_CONFIRM, true); if (display_confirm) { Toasty.success(context, context.getString(R.string.toot_sent), Toast.LENGTH_LONG).show(); } } else { if (apiResponse.getError().getStatusCode() == -33) Toasty.info(context, context.getString(R.string.toast_toot_saved_error), Toast.LENGTH_LONG).show(); } if (apiResponse.getTargetedId() != null && apiResponse.getStatuses() != null && apiResponse.getStatuses().size() > 0) { int position = 0; for (Status tl : this.statuses) { if (tl.getId().equals(apiResponse.getTargetedId())) { List comments = this.statuses.get(position).getComments(); if (comments == null) { comments = new ArrayList<>(); } comments.add(comments.size(), apiResponse.getStatuses().get(0)); this.statuses.get(position).setComments(comments); notifyStatusChanged(this.statuses.get(position)); break; } position++; } } } @Override public void onRetrieveSearchAccounts(APIResponse apiResponse) { if (apiResponse.getError() != null) return; final List accounts = apiResponse.getAccounts(); if (accounts != null && accounts.size() > 0) { int currentCursorPosition = comment_content.getSelectionStart(); AccountsSearchAdapter accountsListAdapter = new AccountsSearchAdapter(context, accounts); comment_content.setThreshold(1); comment_content.setAdapter(accountsListAdapter); final String oldContent = comment_content.getText().toString(); if (oldContent.length() >= currentCursorPosition) { String[] searchA = oldContent.substring(0, currentCursorPosition).split("@"); if (searchA.length > 0) { final String search = searchA[searchA.length - 1]; comment_content.setOnItemClickListener((parent, view, position, id) -> { Account account = accounts.get(position); String deltaSearch = ""; int searchLength = 15; if (currentCursorPosition < 15) { //Less than 15 characters are written before the cursor position searchLength = currentCursorPosition; } if (currentCursorPosition - searchLength > 0 && currentCursorPosition < oldContent.length()) deltaSearch = oldContent.substring(currentCursorPosition - searchLength, currentCursorPosition); else { if (currentCursorPosition >= oldContent.length()) deltaSearch = oldContent.substring(currentCursorPosition - searchLength); } if (!search.equals("")) deltaSearch = deltaSearch.replace("@" + search, ""); String newContent = oldContent.substring(0, currentCursorPosition - searchLength); newContent += deltaSearch; newContent += "@" + account.getAcct() + " "; int newPosition = newContent.length(); if (currentCursorPosition < oldContent.length()) newContent += oldContent.substring(currentCursorPosition); comment_content.setText(newContent); comment_content.setSelection(newPosition); AccountsSearchAdapter accountsListAdapter1 = new AccountsSearchAdapter(context, new ArrayList<>()); comment_content.setThreshold(1); comment_content.setAdapter(accountsListAdapter1); }); } } } } @Override public void onRetrieveContact(APIResponse apiResponse) { } @Override public void onRetrieveSearch(APIResponse apiResponse) { if (apiResponse == null || apiResponse.getResults() == null || comment_content == null) return; app.fedilab.android.client.Entities.Results results = apiResponse.getResults(); int currentCursorPosition = comment_content.getSelectionStart(); final List tags = results.getHashtags(); if (tags != null && tags.size() > 0) { TagsSearchAdapter tagsSearchAdapter = new TagsSearchAdapter(context, tags); comment_content.setThreshold(1); comment_content.setAdapter(tagsSearchAdapter); final String oldContent = comment_content.getText().toString(); if (oldContent.length() < currentCursorPosition) return; String[] searchA = oldContent.substring(0, currentCursorPosition).split("#"); if (searchA.length < 1) return; final String search = searchA[searchA.length - 1]; comment_content.setOnItemClickListener((parent, view, position, id) -> { if (position >= tags.size()) return; String tag = tags.get(position); String deltaSearch = ""; int searchLength = 15; if (currentCursorPosition < 15) { //Less than 15 characters are written before the cursor position searchLength = currentCursorPosition; } if (currentCursorPosition - searchLength > 0 && currentCursorPosition < oldContent.length()) deltaSearch = oldContent.substring(currentCursorPosition - searchLength, currentCursorPosition); else { if (currentCursorPosition >= oldContent.length()) deltaSearch = oldContent.substring(currentCursorPosition - searchLength); } if (!search.equals("")) deltaSearch = deltaSearch.replace("#" + search, ""); String newContent = oldContent.substring(0, currentCursorPosition - searchLength); newContent += deltaSearch; newContent += "#" + tag + " "; int newPosition = newContent.length(); if (currentCursorPosition < oldContent.length()) newContent += oldContent.substring(currentCursorPosition); comment_content.setText(newContent); comment_content.setSelection(newPosition); TagsSearchAdapter tagsSearchAdapter1 = new TagsSearchAdapter(context, new ArrayList<>()); comment_content.setThreshold(1); comment_content.setAdapter(tagsSearchAdapter1); }); } } @Override public void onRetrieveFeeds(APIResponse apiResponse) { if (apiResponse.getStatuses() != null && apiResponse.getStatuses().size() > 0) { SQLiteDatabase db = Sqlite.getInstance(context.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); long id = new StatusStoredDAO(context, db).insertStatus(toot, apiResponse.getStatuses().get(0)); Intent intentToot = new Intent(context, PixelfedComposeActivity.class); Bundle b = new Bundle(); b.putLong("restored", id); b.putBoolean("removed", true); intentToot.putExtras(b); context.startActivity(intentToot); } } public Status getItem(int position) { if (statuses.size() > position && position >= 0) return statuses.get(position); else return null; } @Override public int getItemViewType(int position) { boolean show_account_boosts = false; boolean show_account_replies = false; if (context instanceof ShowAccountActivity) { SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE); show_account_boosts = sharedpreferences.getBoolean(Helper.SHOW_ACCOUNT_BOOSTS, true); show_account_replies = sharedpreferences.getBoolean(Helper.SHOW_ACCOUNT_REPLIES, true); } if (type != RetrieveFeedsAsyncTask.Type.REMOTE_INSTANCE && type != RetrieveFeedsAsyncTask.Type.NEWS && !Helper.filterToots(statuses.get(position), type, context instanceof ShowAccountActivity, show_account_boosts, show_account_replies)) { return HIDDEN_STATUS; } else if (position > 0 && type == RetrieveFeedsAsyncTask.Type.CONTEXT) { return COMMENT_STATUS; } else { return DISPLAYED_STATUS; } } @NonNull @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { context = parent.getContext(); if (viewType == DISPLAYED_STATUS) { DrawerPixelfedBinding itemBinding = DrawerPixelfedBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); return new ViewHolderPixelfed(itemBinding); } else if (viewType == COMMENT_STATUS) { DrawerPixelfedCommentBinding itemBinding = DrawerPixelfedCommentBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); return new ViewHolderPixelfedComment(itemBinding); } else { DrawerEmptyBinding drawerEmptyBinding = DrawerEmptyBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); return new ViewHolderEmpty(drawerEmptyBinding); } } @SuppressLint("SetJavaScriptEnabled") @Override public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder viewHolder, int i) { final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); final String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); if (viewHolder.getItemViewType() == COMMENT_STATUS) { final ViewHolderPixelfedComment holder = (ViewHolderPixelfedComment) viewHolder; final Status status = statuses.get(viewHolder.getAdapterPosition()); if (status.getAccount() != null && status.getAccount().getAvatar() != null) Glide.with(context) .load(status.getAccount().getAvatar()) .apply(new RequestOptions().transform(new FitCenter(), new RoundedCorners(270))) .into(holder.binding.pfPp); int theme_text_header_2_line = prefs.getInt("theme_text_header_2_line", -1); if (theme_text_header_2_line == -1) { theme_text_header_2_line = ThemeHelper.getAttColor(context, R.attr.textHeader); } int theme_text_color = prefs.getInt("theme_text_color", -1); if (theme_text_color != -1) { holder.binding.pfDescription.setTextColor(theme_text_color); } holder.binding.pfUsername.setTextColor(theme_text_header_2_line); holder.binding.pfDate.setTextColor(theme_text_header_2_line); if (status.getAccount().getDisplayNameSpan() != null && status.getAccount().getDisplayNameSpan().toString().trim().length() > 0) holder.binding.pfUsername.setText(status.getAccount().getDisplayNameSpan(), TextView.BufferType.SPANNABLE); else holder.binding.pfUsername.setText(status.getAccount().getUsername()); holder.binding.pfDate.setText(Helper.longDateToString(status.getCreated_at())); holder.binding.pfDescription.setText(status.getContentSpan(), TextView.BufferType.SPANNABLE); } else if (viewHolder.getItemViewType() == DISPLAYED_STATUS) { final ViewHolderPixelfed holder = (ViewHolderPixelfed) viewHolder; final Status status = statuses.get(viewHolder.getAdapterPosition()); if (type == RetrieveFeedsAsyncTask.Type.CONTEXT) { holder.binding.pfBookmark.setVisibility(View.VISIBLE); } if (status.getAccount() != null && status.getAccount().getAvatar() != null) Glide.with(context) .load(status.getAccount().getAvatar()) .apply(new RequestOptions().transform(new FitCenter(), new RoundedCorners(270))) .into(holder.binding.pfPp); int iconColor = prefs.getInt("theme_icons_color", -1); if (iconColor == -1) { iconColor = ThemeHelper.getAttColor(context, R.attr.iconColor); } holder.binding.pfLikes.setTextColor(iconColor); int statusColor = prefs.getInt("theme_statuses_color", -1); if (statusColor != -1) { holder.binding.pfCardview.setCardBackgroundColor(statusColor); } else { holder.binding.pfCardview.setCardBackgroundColor(ThemeHelper.getAttColor(context, R.attr.cardviewColor)); } int theme_text_color = prefs.getInt("theme_text_color", -1); if (theme_text_color != -1) { holder.binding.pfDescription.setTextColor(theme_text_color); } int theme_text_header_2_line = prefs.getInt("theme_text_header_2_line", -1); if (theme_text_header_2_line == -1) { theme_text_header_2_line = ThemeHelper.getAttColor(context, R.attr.textHeader); } holder.binding.pfUsername.setTextColor(theme_text_header_2_line); holder.binding.pfDate.setTextColor(theme_text_header_2_line); if (statusColor != -1) { holder.binding.incQuickReply.quickReplyContainer.setBackgroundColor(statusColor); } holder.binding.incQuickReply.quickReplySwitchToFull.setVisibility(View.GONE); if (status.isShortReply()) { holder.binding.incQuickReply.quickReplyContainer.setVisibility(View.VISIBLE); holder.binding.pixelfedComments.setVisibility(View.VISIBLE); in_reply_to_status = status.getReblog() != null ? status.getReblog().getId() : status.getId(); if (status.isCommentsFetched()) { StatusDrawerParams statusDrawerParams = new StatusDrawerParams(); statusDrawerParams.setPosition(0); statusDrawerParams.setTargetedId(status.getId()); statusDrawerParams.setOnWifi(true); statusDrawerParams.setStatuses(status.getComments()); StatusListAdapter statusListAdapter = new StatusListAdapter(statusDrawerParams); final LinearLayoutManager mLayoutManager; mLayoutManager = new LinearLayoutManager(context); holder.binding.lvComments.setLayoutManager(mLayoutManager); holder.binding.lvComments.setAdapter(statusListAdapter); mLayoutManager.scrollToPositionWithOffset(i, 0); } else { status.setCommentsFetched(true); new RetrieveContextAsyncTask(context, false, false, status.getAccount().getId(), status.getId(), PixelfedListAdapter.this); } InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); assert inputMethodManager != null; inputMethodManager.toggleSoftInputFromWindow( holder.binding.incQuickReply.quickReplyText.getApplicationWindowToken(), InputMethodManager.SHOW_FORCED, 0); EditText content_cw = new EditText(context); content_cw.setText(status.getReblog() != null ? status.getReblog().getSpoiler_text() : status.getSpoiler_text()); String content = TootActivity.manageMentions(userId, status.getReblog() != null ? status.getReblog() : status); TextWatcher textWatcher = PixelfedComposeActivity.initializeTextWatcher(context, social, holder.binding.incQuickReply.quickReplyText, holder.binding.incQuickReply.tootSpaceLeft, null, null, PixelfedListAdapter.this, PixelfedListAdapter.this, PixelfedListAdapter.this); holder.binding.incQuickReply.quickReplyText.addTextChangedListener(textWatcher); holder.binding.incQuickReply.quickReplyText.setText(content); comment_content = holder.binding.incQuickReply.quickReplyText; holder.binding.incQuickReply.quickReplyText.setFocusable(true); holder.binding.incQuickReply.quickReplyText.requestFocus(); holder.binding.incQuickReply.quickReplyText.setSelection(content.length()); //Put cursor at the end int newInputType = comment_content.getInputType() & (comment_content.getInputType() ^ InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE); comment_content.setInputType(newInputType); in_reply_to_status = status.getReblog() != null ? status.getReblog().getId() : status.getId(); final SQLiteDatabase db = Sqlite.getInstance(context.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); String instance = sharedpreferences.getString(Helper.PREF_INSTANCE, null); Account account = new AccountDAO(context, db).getUniqAccount(userId, instance); String defaultVisibility = account.isLocked() ? "private" : "public"; String settingsVisibility = sharedpreferences.getString(Helper.SET_TOOT_VISIBILITY + "@" + account.getAcct() + "@" + account.getInstance(), defaultVisibility); int initialTootVisibility = 0; int ownerTootVisibility = 0; switch (status.getReblog() != null ? status.getReblog().getVisibility() : status.getVisibility()) { case "public": initialTootVisibility = 4; break; case "unlisted": initialTootVisibility = 3; break; case "private": visibility = "private"; initialTootVisibility = 2; break; case "direct": visibility = "direct"; initialTootVisibility = 1; break; } switch (settingsVisibility) { case "public": ownerTootVisibility = 4; break; case "unlisted": ownerTootVisibility = 3; break; case "private": visibility = "private"; ownerTootVisibility = 2; break; case "direct": visibility = "direct"; ownerTootVisibility = 1; break; } int tootVisibility = Math.min(ownerTootVisibility, initialTootVisibility); switch (tootVisibility) { case 4: visibility = "public"; holder.binding.incQuickReply.quickReplyPrivacy.setImageResource(R.drawable.ic_public_toot); break; case 3: visibility = "unlisted"; holder.binding.incQuickReply.quickReplyPrivacy.setImageResource(R.drawable.ic_lock_open_toot); break; case 2: visibility = "private"; holder.binding.incQuickReply.quickReplyPrivacy.setImageResource(R.drawable.ic_lock_outline_toot); break; case 1: visibility = "direct"; holder.binding.incQuickReply.quickReplyPrivacy.setImageResource(R.drawable.ic_mail_outline_toot); break; } } else { holder.binding.incQuickReply.quickReplyContainer.setVisibility(View.GONE); holder.binding.pixelfedComments.setVisibility(View.GONE); } holder.binding.artMediaPlay.setVisibility(View.GONE); boolean expand_media = sharedpreferences.getBoolean(Helper.SET_EXPAND_MEDIA, false); holder.binding.artMedia.setOnClickListener(v -> { if (expand_media || !status.isSensitive() || status.isAttachmentShown()) { Intent intent = new Intent(context, SlideMediaActivity.class); Bundle b = new Bundle(); intent.putParcelableArrayListExtra("mediaArray", status.getMedia_attachments()); b.putInt("position", 1); b.putInt("bgcolor", context.getResources().getColor(R.color.cyanea_primary_dark)); intent.putExtras(b); if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { ActivityOptionsCompat options = ActivityOptionsCompat .makeSceneTransitionAnimation((Activity) context, holder.binding.artMedia, status.getMedia_attachments().get(0).getUrl()); // start the new activity context.startActivity(intent, options.toBundle()); } else { // start the new activity context.startActivity(intent); } } else { status.setAttachmentShown(true); notifyItemChanged(i); final int timeout = sharedpreferences.getInt(Helper.SET_NSFW_TIMEOUT, 5); if (timeout > 0) { new CountDownTimer((timeout * 1000), 1000) { public void onTick(long millisUntilFinished) { } public void onFinish() { status.setAttachmentShown(false); notifyItemChanged(i); } }.start(); } } }); if (status.getMedia_attachments() != null && status.getMedia_attachments().size() > 1) { SliderAdapter sliderAdapter = new SliderAdapter(new WeakReference<>((Activity) context), false, status); holder.binding.imageSlider.setSliderAdapter(sliderAdapter); holder.binding.imageSlider.setIndicatorAnimation(IndicatorAnimations.WORM); holder.binding.imageSlider.setSliderTransformAnimation(SliderAnimations.SIMPLETRANSFORMATION); holder.binding.artMedia.setVisibility(View.GONE); holder.binding.imageSlider.setVisibility(View.VISIBLE); } else if (status.getMedia_attachments() != null && status.getMedia_attachments().size() > 0) { holder.binding.artMedia.setVisibility(View.VISIBLE); holder.binding.imageSlider.setVisibility(View.GONE); if (status.getMedia_attachments().get(0).getType() != null && status.getMedia_attachments().get(0).getType().toLowerCase().equals("video")) { holder.binding.artMediaPlay.setVisibility(View.VISIBLE); } String url; if (status.getMedia_attachments().get(0).getPreview_url() != null && status.getMedia_attachments().get(0).getPreview_url().endsWith("no-preview.png")) { url = status.getMedia_attachments().get(0).getUrl(); } else { url = status.getMedia_attachments().get(0).getPreview_url(); } if (expand_media || !status.isSensitive() || status.isAttachmentShown()) { Glide.with(holder.itemView.getContext()) .asBitmap() .load(url) .thumbnail(0.1f) .into(holder.binding.artMedia); } else { Glide.with(holder.itemView.getContext()) .asBitmap() .load(url) .apply(new RequestOptions().transform(new BlurTransformation(50, 3))) .thumbnail(0.1f) .into(holder.binding.artMedia); } } holder.binding.pfLikes.setText(context.getResources().getQuantityString(R.plurals.likes, status.getFavourites_count(), status.getFavourites_count())); holder.binding.pfPp.setOnClickListener(v -> { if (MainActivity.social != UpdateAccountInfoAsyncTask.SOCIAL.PIXELFED) { CrossActions.doCrossProfile(context, status.getAccount()); } else { Intent intent = new Intent(context, ShowAccountActivity.class); Bundle b = new Bundle(); b.putParcelable("account", status.getAccount()); intent.putExtras(b); context.startActivity(intent); } }); holder.binding.incQuickReply.quickReplySwitchToFull.setVisibility(View.GONE); holder.binding.incQuickReply.tootSpaceLeft.setVisibility(View.GONE); holder.binding.incQuickReply.quickReplyEmoji.setVisibility(View.GONE); holder.binding.incQuickReply.quickReplyPrivacy.setVisibility(View.GONE); holder.binding.incQuickReply.quickReplyButton.setOnClickListener(view -> { sendToot(status); status.setShortReply(false); holder.binding.incQuickReply.quickReplyContainer.setVisibility(View.GONE); InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE); assert imm != null; imm.hideSoftInputFromWindow(holder.binding.incQuickReply.quickReplyButton.getWindowToken(), 0); }); holder.binding.pfDescription.setText(status.getContentSpan(), TextView.BufferType.SPANNABLE); holder.binding.pfDate.setText(Helper.longDateToString(status.getCreated_at())); holder.binding.incQuickReply.quickReplyText.setHint(R.string.leave_a_comment); holder.binding.incQuickReply.quickReplyButton.setText(R.string.post); holder.binding.pfComment.setOnClickListener(v -> { boolean currentValue = status.isShortReply(); for (Status s : statuses) { if (s.isShortReply() && !s.getId().equals(status.getId())) { s.setShortReply(false); notifyStatusChanged(s); } } status.setShortReply(!currentValue); if (!status.isShortReply()) { InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE); assert imm != null; imm.hideSoftInputFromWindow(holder.binding.incQuickReply.quickReplyText.getWindowToken(), 0); } notifyStatusChanged(status); }); final View attached = holder.binding.statusMore; holder.binding.statusMore.setOnClickListener(v -> { PopupMenu popup = new PopupMenu(context, attached); final boolean isOwner = status.getReblog() != null ? status.getReblog().getAccount().getId().equals(userId) : status.getAccount().getId().equals(userId); popup.getMenuInflater() .inflate(R.menu.option_pixelfed, popup.getMenu()); final String[] stringArrayConf; if (status.getVisibility().equals("direct") || (status.getVisibility().equals("private") && !isOwner)) popup.getMenu().findItem(R.id.action_schedule_boost).setVisible(false); if (isOwner) { popup.getMenu().findItem(R.id.action_block).setVisible(false); popup.getMenu().findItem(R.id.action_mute).setVisible(false); stringArrayConf = context.getResources().getStringArray(R.array.more_action_owner_confirm); } else { popup.getMenu().findItem(R.id.action_remove).setVisible(false); //Same instance stringArrayConf = context.getResources().getStringArray(R.array.more_action_confirm); } final SharedPreferences sharedpreferences1 = context.getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE); int theme = sharedpreferences1.getInt(Helper.SET_THEME, Helper.THEME_DARK); int style; if (theme == Helper.THEME_DARK) { style = R.style.DialogDark; } else if (theme == Helper.THEME_BLACK) { style = R.style.DialogBlack; } else { style = R.style.Dialog; } popup.setOnMenuItemClickListener(item -> { AlertDialog.Builder builderInner; final API.StatusAction doAction; int itemId = item.getItemId(); if (itemId == R.id.action_info) { tootInformation(status); return true; } else if (itemId == R.id.action_open_browser) { Helper.openBrowser(context, status.getReblog() != null ? status.getReblog().getUrl() : status.getUrl()); return true; } else if (itemId == R.id.action_remove) { builderInner = new AlertDialog.Builder(context, style); builderInner.setTitle(stringArrayConf[0]); doAction = API.StatusAction.UNSTATUS; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) builderInner.setMessage(Html.fromHtml(status.getContent(), Html.FROM_HTML_MODE_LEGACY)); else builderInner.setMessage(Html.fromHtml(status.getContent())); } else if (itemId == R.id.action_mute) { builderInner = new AlertDialog.Builder(context, style); builderInner.setTitle(stringArrayConf[0]); builderInner.setMessage(status.getAccount().getAcct()); doAction = API.StatusAction.MUTE; } else if (itemId == R.id.action_block) { builderInner = new AlertDialog.Builder(context, style); builderInner.setTitle(stringArrayConf[1]); doAction = API.StatusAction.BLOCK; } else if (itemId == R.id.action_translate) { int translator = sharedpreferences1.getInt(Helper.SET_TRANSLATOR, Helper.TRANS_LIBRETRANSLATE); if (translator == Helper.TRANS_NONE) Toasty.info(context, R.string.toast_error_translations_disabled, Toast.LENGTH_SHORT).show(); else translateToot(status); return true; } else if (itemId == R.id.action_copy_link) { ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); ClipData clip = ClipData.newPlainText(Helper.CLIP_BOARD, status.getReblog() != null ? status.getReblog().getUrl() : status.getUrl()); if (clipboard != null) { clipboard.setPrimaryClip(clip); Toasty.info(context, context.getString(R.string.clipboard_url), Toast.LENGTH_LONG).show(); } return true; } else if (itemId == R.id.action_share) { Intent sendIntent = new Intent(Intent.ACTION_SEND); sendIntent.putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.shared_via)); String url; if (status.getReblog() != null) { if (status.getReblog().getUri().startsWith("http")) url = status.getReblog().getUri(); else url = status.getReblog().getUrl(); } else { if (status.getUri().startsWith("http")) url = status.getUri(); else url = status.getUrl(); } String extra_text; boolean share_details = sharedpreferences1.getBoolean(Helper.SET_SHARE_DETAILS, true); if (share_details) { extra_text = (status.getReblog() != null) ? status.getReblog().getAccount().getAcct() : status.getAccount().getAcct(); if (extra_text.split("@").length == 1) extra_text = "@" + extra_text + "@" + Helper.getLiveInstance(context); else extra_text = "@" + extra_text; extra_text += " \uD83D\uDD17 " + url + "\r\n-\n"; final String contentToot; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) contentToot = Html.fromHtml((status.getReblog() != null) ? status.getReblog().getContent() : status.getContent(), Html.FROM_HTML_MODE_LEGACY).toString(); else contentToot = Html.fromHtml((status.getReblog() != null) ? status.getReblog().getContent() : status.getContent()).toString(); extra_text += contentToot; } else { extra_text = url; } sendIntent.putExtra(Intent.EXTRA_TEXT, extra_text); sendIntent.setType("text/plain"); context.startActivity(Intent.createChooser(sendIntent, context.getString(R.string.share_with))); return true; } else { return true; } builderInner.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss()); builderInner.setPositiveButton(R.string.yes, (dialog, which) -> { if (doAction == API.StatusAction.UNSTATUS) { String targetedId = status.getId(); new PostActionAsyncTask(context, doAction, targetedId, PixelfedListAdapter.this); if (redraft) { if (status.getIn_reply_to_id() != null && !status.getIn_reply_to_id().trim().equals("null")) { toot = new Status(); toot.setIn_reply_to_id(status.getIn_reply_to_id()); toot.setSensitive(status.isSensitive()); toot.setMedia_attachments(status.getMedia_attachments()); if (status.getSpoiler_text() != null && status.getSpoiler_text().length() > 0) toot.setSpoiler_text(status.getSpoiler_text().trim()); toot.setContent(context, status.getContent()); toot.setVisibility(status.getVisibility()); if (status.getPoll() != null) { toot.setPoll(status.getPoll()); } else if (status.getReblog() != null && status.getReblog().getPoll() != null) { toot.setPoll(status.getPoll()); } new RetrieveFeedsAsyncTask(context, RetrieveFeedsAsyncTask.Type.ONESTATUS, status.getIn_reply_to_id(), null, false, false, PixelfedListAdapter.this); } else { toot = new Status(); toot.setSensitive(status.isSensitive()); toot.setMedia_attachments(status.getMedia_attachments()); if (status.getSpoiler_text() != null && status.getSpoiler_text().length() > 0) toot.setSpoiler_text(status.getSpoiler_text().trim()); toot.setVisibility(status.getVisibility()); toot.setContent(context, status.getContent()); if (status.getPoll() != null) { toot.setPoll(status.getPoll()); } else if (status.getReblog() != null && status.getReblog().getPoll() != null) { toot.setPoll(status.getPoll()); } final SQLiteDatabase db = Sqlite.getInstance(context.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); long id = new StatusStoredDAO(context, db).insertStatus(toot, null); Intent intentToot = new Intent(context, PixelfedComposeActivity.class); Bundle b = new Bundle(); b.putLong("restored", id); b.putBoolean("removed", true); intentToot.putExtras(b); context.startActivity(intentToot); } } } else { String targetedId; if (item.getItemId() == R.id.action_block_domain) { targetedId = status.getAccount().getAcct().split("@")[1]; } else { targetedId = status.getAccount().getId(); } new PostActionAsyncTask(context, doAction, targetedId, PixelfedListAdapter.this); } dialog.dismiss(); }); builderInner.show(); return true; }); popup.show(); }); holder.binding.pfCardview.setOnClickListener(view -> { //For Pixelfed conversations can't be open several times if (type != RetrieveFeedsAsyncTask.Type.CONTEXT) { Intent intent = new Intent(context, ShowConversationActivity.class); Bundle b = new Bundle(); if (status.getReblog() == null) b.putParcelable("status", status); else b.putParcelable("status", status.getReblog()); intent.putExtras(b); context.startActivity(intent); } }); if (status.getAccount().getDisplayNameSpan() != null && status.getAccount().getDisplayNameSpan().toString().trim().length() > 0) holder.binding.pfUsername.setText(status.getAccount().getDisplayNameSpan(), TextView.BufferType.SPANNABLE); else holder.binding.pfUsername.setText(status.getAccount().getUsername()); holder.binding.pfFav.setInActiveImageTintColor(iconColor); holder.binding.pfShare.setInActiveImageTintColor(iconColor); holder.binding.pfBookmark.setInActiveImageTintColor(iconColor); Helper.changeDrawableColor(context, holder.binding.pfComment, iconColor); Helper.changeDrawableColor(context, holder.binding.statusMore, iconColor); Helper.changeDrawableColor(context, R.drawable.ic_pixelfed_favorite_border, iconColor); holder.binding.pfFav.pressOnTouch(false); holder.binding.pfFav.setActiveImage(R.drawable.ic_pixelfed_favorite); holder.binding.pfFav.setInactiveImage(R.drawable.ic_pixelfed_favorite_border); holder.binding.pfFav.setDisableCircle(true); holder.binding.pfFav.setActiveImageTint(R.color.pixelfed_like); holder.binding.pfFav.setColors(R.color.pixelfed_like, R.color.pixelfed_like); holder.binding.pfShare.pressOnTouch(false); holder.binding.pfShare.setActiveImage(R.drawable.ic_repeat_boost); holder.binding.pfShare.setInactiveImage(R.drawable.ic_repeat_boost); holder.binding.pfShare.setDisableCircle(true); holder.binding.pfShare.setActiveImageTint(R.color.boost_icon); holder.binding.pfShare.setColors(R.color.boost_icon, R.color.boost_icon); holder.binding.pfBookmark.pressOnTouch(false); holder.binding.pfBookmark.setActiveImage(R.drawable.ic_bookmark_white_full); holder.binding.pfBookmark.setInactiveImage(R.drawable.ic_bookmark_white); holder.binding.pfBookmark.setDisableCircle(true); holder.binding.pfBookmark.setActiveImageTint(R.color.marked_icon); holder.binding.pfBookmark.setColors(R.color.marked_icon, R.color.marked_icon); if (!status.isFavAnimated()) { holder.binding.pfFav.setChecked(status.isFavourited() || (status.getReblog() != null && status.getReblog().isFavourited())); } else { status.setFavAnimated(false); holder.binding.pfFav.setChecked(true); holder.binding.pfFav.setAnimationSpeed(1.0f); holder.binding.pfFav.playAnimation(); } if (!status.isBoostAnimated()) { holder.binding.pfShare.setChecked(status.isReblogged() || (status.getReblog() != null && status.getReblog().isReblogged())); } else { status.setBoostAnimated(false); holder.binding.pfShare.setChecked(true); holder.binding.pfShare.setAnimationSpeed(1.0f); holder.binding.pfShare.playAnimation(); } if (!status.isBookmarkAnimated()) { holder.binding.pfBookmark.setChecked(status.isBookmarked() || (status.getReblog() != null && status.getReblog().isBookmarked())); } else { status.setBookmarkAnimated(false); holder.binding.pfBookmark.setChecked(true); holder.binding.pfBookmark.setAnimationSpeed(1.0f); holder.binding.pfBookmark.playAnimation(); } boolean confirmFav = sharedpreferences.getBoolean(Helper.SET_NOTIF_VALIDATION_FAV, false); holder.binding.pfFav.setOnClickListener(v -> { if (!status.isFavourited() && confirmFav) status.setFavAnimated(true); if (!status.isFavourited() && !confirmFav) { status.setFavAnimated(true); notifyStatusChanged(status); } CrossActions.doCrossAction(context, type, status, null, (status.isFavourited() || (status.getReblog() != null && status.getReblog().isFavourited())) ? API.StatusAction.UNFAVOURITE : API.StatusAction.FAVOURITE, this, PixelfedListAdapter.this, true); }); boolean confirmBoost = sharedpreferences.getBoolean(Helper.SET_NOTIF_VALIDATION, false); holder.binding.pfShare.setOnClickListener(v -> { if (!status.isReblogged() && confirmBoost) status.setBoostAnimated(true); if (!status.isReblogged() && !confirmBoost) { status.setBoostAnimated(true); notifyStatusChanged(status); } CrossActions.doCrossAction(context, type, status, null, (status.isReblogged() || (status.getReblog() != null && status.getReblog().isReblogged())) ? API.StatusAction.UNREBLOG : API.StatusAction.REBLOG, this, PixelfedListAdapter.this, true); }); holder.binding.pfBookmark.setOnClickListener(v -> { if (!status.isBookmarked()) { status.setBookmarkAnimated(true); notifyStatusChanged(status); } CrossActions.doCrossAction(context, type, status, null, (status.isBookmarked() || (status.getReblog() != null && status.getReblog().isBookmarked())) ? API.StatusAction.UNBOOKMARK : API.StatusAction.BOOKMARK, this, PixelfedListAdapter.this, true); }); } } @Override public void onPostAction(int statusCode, API.StatusAction statusAction, String targetedId, Error error) { if (error != null) { Toasty.error(context, error.getError(), Toast.LENGTH_LONG).show(); return; } Helper.manageMessageStatusCode(context, statusCode, statusAction); //When muting or blocking an account, its status are removed from the list List statusesToRemove = new ArrayList<>(); if (statusAction == API.StatusAction.MUTE || statusAction == API.StatusAction.BLOCK) { for (Status status : statuses) { if (status.getAccount().getId().equals(targetedId)) statusesToRemove.add(status); } statuses.removeAll(statusesToRemove); notifyDataSetChanged(); } else if (statusAction == API.StatusAction.UNSTATUS) { int position = 0; for (Status status : statuses) { if (status.getId().equals(targetedId)) { statuses.remove(status); notifyItemRemoved(position); SQLiteDatabase db = Sqlite.getInstance(context.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); //Remove the status from cache also try { new StatusCacheDAO(context, db).remove(StatusCacheDAO.ARCHIVE_CACHE, status); } catch (Exception ignored) { } break; } position++; } } else if (statusAction == API.StatusAction.PIN || statusAction == API.StatusAction.UNPIN) { int position = 0; for (Status status : statuses) { if (status.getId().equals(targetedId)) { status.setPinned(statusAction == API.StatusAction.PIN); notifyItemChanged(position); break; } position++; } } } private void send_delete_statuses(String targetedId) { //Delete in the current timeline List statusesToRemove = new ArrayList<>(); for (Status status : statuses) { if (status.getAccount().getId().equals(targetedId)) statusesToRemove.add(status); } statuses.removeAll(statusesToRemove); notifyDataSetChanged(); //Send an intent to delete in every timelines Bundle b = new Bundle(); b.putString("receive_action", targetedId); Intent intentBC = new Intent(Helper.RECEIVE_ACTION); intentBC.putExtras(b); } public void notifyStatusChanged(Status status) { for (int i = 0; i < getItemCount(); i++) { if (getItemAt(i) != null && getItemAt(i).getId().equals(status.getId())) { try { notifyItemChanged(i); } catch (Exception ignored) { } } } } private void translateToot(Status status) { //Manages translations SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE); int trans = sharedpreferences.getInt(Helper.SET_TRANSLATOR, Helper.TRANS_LIBRETRANSLATE); MyTransL.translatorEngine et = MyTransL.translatorEngine.YANDEX; String api_key; if (trans == Helper.TRANS_DEEPL) { et = MyTransL.translatorEngine.DEEPL; } else if (trans == Helper.TRANS_SYSTRAN) { et = MyTransL.translatorEngine.SYSTRAN; } final MyTransL myTransL = MyTransL.getInstance(et); myTransL.setObfuscation(true); if (trans == Helper.TRANS_YANDEX) { api_key = sharedpreferences.getString(Helper.SET_YANDEX_API_KEY, Helper.YANDEX_KEY); myTransL.setYandexAPIKey(api_key); } else if (trans == Helper.TRANS_DEEPL) { api_key = sharedpreferences.getString(Helper.SET_DEEPL_API_KEY, ""); myTransL.setDeeplAPIKey(api_key); } else if (trans == Helper.TRANS_SYSTRAN) { api_key = sharedpreferences.getString(Helper.SET_SYSTRAN_API_KEY, ""); myTransL.setSystranAPIKey(api_key); } if (!status.isTranslated()) { String statusToTranslate; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) statusToTranslate = Html.fromHtml(status.getReblog() != null ? status.getReblog().getContent() : status.getContent(), Html.FROM_HTML_MODE_LEGACY).toString(); else statusToTranslate = Html.fromHtml(status.getReblog() != null ? status.getReblog().getContent() : status.getContent()).toString(); //TODO: removes the replaceAll once fixed with the lib myTransL.translate(statusToTranslate, MyTransL.getLocale(), new Results() { @Override public void onSuccess(Translate translate) { if (translate.getTranslatedContent() != null) { status.setTranslated(true); status.setTranslationShown(true); status.setContentTranslated(translate.getTranslatedContent()); Status.transformTranslation(context, status); //makeEmojis(context, view, status.getContentSpan(), status.getReblog()!=null?status.getReblog().getEmojis():status.getEmojis()); notifyStatusChanged(status); } else { Toasty.error(context, context.getString(R.string.toast_error_translate), Toast.LENGTH_LONG).show(); } } @Override public void onFail(HttpsConnectionException e) { e.printStackTrace(); Toasty.error(context, context.getString(R.string.toast_error_translate), Toast.LENGTH_LONG).show(); } }); } else { status.setTranslationShown(!status.isTranslationShown()); notifyStatusChanged(status); } } private void tootInformation(Status status) { Intent intent = new Intent(context, TootInfoActivity.class); Bundle b = new Bundle(); if (status.getReblog() != null) { b.putString("toot_id", status.getReblog().getId()); b.putInt("toot_reblogs_count", status.getReblog().getReblogs_count()); b.putInt("toot_favorites_count", status.getReblog().getFavourites_count()); } else { b.putString("toot_id", status.getId()); b.putInt("toot_reblogs_count", status.getReblogs_count()); b.putInt("toot_favorites_count", status.getFavourites_count()); } intent.putExtras(b); context.startActivity(intent); } private void sendToot(Status status) { if (comment_content.getText() == null) { Toasty.error(context, context.getString(R.string.toast_error), Toast.LENGTH_LONG).show(); return; } if (comment_content.getText().toString().trim().length() == 0) { Toasty.error(context, context.getString(R.string.toot_error_no_content), Toast.LENGTH_LONG).show(); return; } SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE); final String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); String instance = Helper.getLiveInstance(context); String tootContent; tootContent = comment_content.getText().toString().trim(); Status toot = new Status(); toot.setSensitive(false); final SQLiteDatabase db = Sqlite.getInstance(context.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); Account account = new AccountDAO(context, db).getUniqAccount(userId, instance); toot.setVisibility(visibility); toot.setIn_reply_to_id(in_reply_to_status); toot.setContent(context, tootContent); new PostStatusAsyncTask(context, social, account, toot, PixelfedListAdapter.this); status.setQuickReplyPrivacy(null); status.setQuickReplyContent(null); } static class ViewHolderEmpty extends RecyclerView.ViewHolder { DrawerEmptyBinding binding; ViewHolderEmpty(DrawerEmptyBinding itemView) { super(itemView.getRoot()); binding = itemView; } } private void timedMuteAction(Status status) { final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE); int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK); int style; if (theme == Helper.THEME_DARK) { style = R.style.DialogDark; } else if (theme == Helper.THEME_BLACK) { style = R.style.DialogBlack; } else { style = R.style.Dialog; } AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context, style); LayoutInflater inflater = ((Activity) context).getLayoutInflater(); View dialogView = inflater.inflate(R.layout.datetime_picker, new LinearLayout(context), false); dialogBuilder.setView(dialogView); final AlertDialog alertDialog = dialogBuilder.create(); final DatePicker datePicker = dialogView.findViewById(R.id.date_picker); final TimePicker timePicker = dialogView.findViewById(R.id.time_picker); timePicker.setIs24HourView(true); Button date_time_cancel = dialogView.findViewById(R.id.date_time_cancel); final ImageButton date_time_previous = dialogView.findViewById(R.id.date_time_previous); final ImageButton date_time_next = dialogView.findViewById(R.id.date_time_next); final ImageButton date_time_set = dialogView.findViewById(R.id.date_time_set); //Buttons management date_time_cancel.setOnClickListener(v -> alertDialog.dismiss()); date_time_next.setOnClickListener(v -> { datePicker.setVisibility(View.GONE); timePicker.setVisibility(View.VISIBLE); date_time_previous.setVisibility(View.VISIBLE); date_time_next.setVisibility(View.GONE); date_time_set.setVisibility(View.VISIBLE); }); date_time_previous.setOnClickListener(v -> { datePicker.setVisibility(View.VISIBLE); timePicker.setVisibility(View.GONE); date_time_previous.setVisibility(View.GONE); date_time_next.setVisibility(View.VISIBLE); date_time_set.setVisibility(View.GONE); }); date_time_set.setOnClickListener(v -> { int hour, minute; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { hour = timePicker.getHour(); minute = timePicker.getMinute(); } else { hour = timePicker.getCurrentHour(); minute = timePicker.getCurrentMinute(); } Calendar calendar = new GregorianCalendar(datePicker.getYear(), datePicker.getMonth(), datePicker.getDayOfMonth(), hour, minute); long time = calendar.getTimeInMillis(); if ((time - new Date().getTime()) < 60000) { Toasty.error(context, context.getString(R.string.timed_mute_date_error), Toast.LENGTH_LONG).show(); } else { //Store the toot as draft first String targeted_id = status.getAccount().getId(); Date date_mute = new Date(time); SQLiteDatabase db = Sqlite.getInstance(context.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); String instance = sharedpreferences.getString(Helper.PREF_INSTANCE, null); String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); Account account = new AccountDAO(context, db).getUniqAccount(userId, instance); new TempMuteDAO(context, db).insert(account, targeted_id, new Date(time)); if (mutedAccount != null && !mutedAccount.contains(account.getId())) mutedAccount.add(targeted_id); else if (mutedAccount == null) { mutedAccount = new ArrayList<>(); mutedAccount.add(targeted_id); } Toasty.success(context, context.getString(R.string.timed_mute_date, status.getAccount().getAcct(), Helper.dateToString(date_mute)), Toast.LENGTH_LONG).show(); alertDialog.dismiss(); send_delete_statuses(targeted_id); } }); alertDialog.show(); } static class ViewHolderPixelfed extends RecyclerView.ViewHolder { DrawerPixelfedBinding binding; ViewHolderPixelfed(DrawerPixelfedBinding itemView) { super(itemView.getRoot()); binding = itemView; } } private void scheduleBoost(Status status) { final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE); int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK); int style; if (theme == Helper.THEME_DARK) { style = R.style.DialogDark; } else if (theme == Helper.THEME_BLACK) { style = R.style.DialogBlack; } else { style = R.style.Dialog; } AlertDialog.Builder dialogBuilderBoost = new AlertDialog.Builder(context, style); LayoutInflater inflaterBoost = ((Activity) context).getLayoutInflater(); View dialogViewBoost = inflaterBoost.inflate(R.layout.datetime_picker, new LinearLayout(context), false); dialogBuilderBoost.setView(dialogViewBoost); final AlertDialog alertDialogBoost = dialogBuilderBoost.create(); final DatePicker datePickerBoost = dialogViewBoost.findViewById(R.id.date_picker); final TimePicker timePickerBoost = dialogViewBoost.findViewById(R.id.time_picker); timePickerBoost.setIs24HourView(true); Button date_time_cancelBoost = dialogViewBoost.findViewById(R.id.date_time_cancel); final ImageButton date_time_previousBoost = dialogViewBoost.findViewById(R.id.date_time_previous); final ImageButton date_time_nextBoost = dialogViewBoost.findViewById(R.id.date_time_next); final ImageButton date_time_setBoost = dialogViewBoost.findViewById(R.id.date_time_set); //Buttons management date_time_cancelBoost.setOnClickListener(v -> alertDialogBoost.dismiss()); date_time_nextBoost.setOnClickListener(v -> { datePickerBoost.setVisibility(View.GONE); timePickerBoost.setVisibility(View.VISIBLE); date_time_previousBoost.setVisibility(View.VISIBLE); date_time_nextBoost.setVisibility(View.GONE); date_time_setBoost.setVisibility(View.VISIBLE); }); date_time_previousBoost.setOnClickListener(v -> { datePickerBoost.setVisibility(View.VISIBLE); timePickerBoost.setVisibility(View.GONE); date_time_previousBoost.setVisibility(View.GONE); date_time_nextBoost.setVisibility(View.VISIBLE); date_time_setBoost.setVisibility(View.GONE); }); date_time_setBoost.setOnClickListener(v -> { int hour, minute; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { hour = timePickerBoost.getHour(); minute = timePickerBoost.getMinute(); } else { hour = timePickerBoost.getCurrentHour(); minute = timePickerBoost.getCurrentMinute(); } Calendar calendar = new GregorianCalendar(datePickerBoost.getYear(), datePickerBoost.getMonth(), datePickerBoost.getDayOfMonth(), hour, minute); long time = calendar.getTimeInMillis(); if ((time - new Date().getTime()) < 60000) { Toasty.warning(context, context.getString(R.string.toot_scheduled_date), Toast.LENGTH_LONG).show(); } else { //Schedules the toot ScheduledBoostsSyncJob.schedule(context, status, time); //Clear content Toasty.info(context, context.getString(R.string.boost_scheduled), Toast.LENGTH_LONG).show(); alertDialogBoost.dismiss(); } }); alertDialogBoost.show(); } static class ViewHolderPixelfedComment extends RecyclerView.ViewHolder { DrawerPixelfedCommentBinding binding; ViewHolderPixelfedComment(DrawerPixelfedCommentBinding itemView) { super(itemView.getRoot()); binding = itemView; } } @Override public void onRetrieveEmoji(Status status, boolean fromTranslation) { if (status != null) { if (!fromTranslation) { status.setEmojiFound(true); } else { status.setEmojiTranslateFound(true); } notifyStatusChanged(status); } } @Override public void onRetrieveEmoji(Notification notification) { } @Override public void onRetrieveSearchEmoji(List emojis) { } }