Improvements for Pleroma/Akkoma (#445)
* Reply Visibility on Plemora * Sort statuses in thread * Get default visibility and language from account if preferences fail * Fix for Mentions tab in notifications on Pleroma * Mark status as sensitive if not already when spoilertext is present * Integrating Pleroma quoting for new posts * move string to strings_sk * use null instead of empty string * change string * fix crash due to null value * update string --------- Co-authored-by: sk <sk22@mailbox.org>
This commit is contained in:
@@ -204,6 +204,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
private List<EmojiCategory> customEmojis;
|
||||
private CustomEmojiPopupKeyboard emojiKeyboard;
|
||||
private Status replyTo;
|
||||
private Status quote;
|
||||
private String initialText;
|
||||
private String uuid;
|
||||
private int pollDuration=24*3600;
|
||||
@@ -252,6 +253,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
editingStatus=Parcels.unwrap(getArguments().getParcelable("editStatus"));
|
||||
if(getArguments().containsKey("replyTo"))
|
||||
replyTo=Parcels.unwrap(getArguments().getParcelable("replyTo"));
|
||||
if(getArguments().containsKey("quote"))
|
||||
quote=Parcels.unwrap(getArguments().getParcelable("quote"));
|
||||
if(instance==null){
|
||||
Nav.finish(this);
|
||||
return;
|
||||
@@ -607,7 +610,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
}
|
||||
});
|
||||
spoilerEdit.addTextChangedListener(new SimpleTextWatcher(e->updateCharCounter()));
|
||||
if(replyTo!=null){
|
||||
if(replyTo!=null || quote!=null){
|
||||
Status status = quote!=null ? quote : replyTo;
|
||||
View replyWrap = view.findViewById(R.id.reply_wrap);
|
||||
scrollView.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
|
||||
int scrollHeight = scrollView.getHeight();
|
||||
@@ -633,13 +637,13 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
originalPost.setOnClickListener(v->{
|
||||
Bundle args=new Bundle();
|
||||
args.putString("account", accountID);
|
||||
args.putParcelable("status", Parcels.wrap(replyTo));
|
||||
args.putParcelable("status", Parcels.wrap(status));
|
||||
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
|
||||
Nav.go(getActivity(), ThreadFragment.class, args);
|
||||
});
|
||||
|
||||
ImageView avatar = view.findViewById(R.id.avatar);
|
||||
ViewImageLoader.load(avatar, null, new UrlImageLoaderRequest(replyTo.account.avatar));
|
||||
ViewImageLoader.load(avatar, null, new UrlImageLoaderRequest(status.account.avatar));
|
||||
ViewOutlineProvider roundCornersOutline=new ViewOutlineProvider(){
|
||||
@Override
|
||||
public void getOutline(View view, Outline outline){
|
||||
@@ -651,15 +655,15 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
avatar.setOnClickListener(v->{
|
||||
Bundle args=new Bundle();
|
||||
args.putString("account", accountID);
|
||||
args.putParcelable("profileAccount", Parcels.wrap(replyTo.account));
|
||||
args.putParcelable("profileAccount", Parcels.wrap(status.account));
|
||||
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
|
||||
Nav.go(getActivity(), ProfileFragment.class, args);
|
||||
});
|
||||
|
||||
((TextView) view.findViewById(R.id.name)).setText(replyTo.account.displayName);
|
||||
((TextView) view.findViewById(R.id.username)).setText(replyTo.account.getDisplayUsername());
|
||||
((TextView) view.findViewById(R.id.name)).setText(status.account.displayName);
|
||||
((TextView) view.findViewById(R.id.username)).setText(status.account.getDisplayUsername());
|
||||
view.findViewById(R.id.visibility).setVisibility(View.GONE);
|
||||
Drawable visibilityIcon = getActivity().getDrawable(switch(replyTo.visibility){
|
||||
Drawable visibilityIcon = getActivity().getDrawable(switch(status.visibility){
|
||||
case PUBLIC -> R.drawable.ic_fluent_earth_20_regular;
|
||||
case UNLISTED -> R.drawable.ic_fluent_lock_open_20_regular;
|
||||
case PRIVATE -> R.drawable.ic_fluent_lock_closed_20_filled;
|
||||
@@ -670,36 +674,36 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
moreBtn.setImageDrawable(visibilityIcon);
|
||||
moreBtn.setBackground(null);
|
||||
TextView timestamp = view.findViewById(R.id.timestamp);
|
||||
if (replyTo.editedAt==null) timestamp.setText(UiUtils.formatRelativeTimestamp(getContext(), replyTo.createdAt));
|
||||
else timestamp.setText(getString(R.string.edited_timestamp, UiUtils.formatRelativeTimestamp(getContext(), replyTo.editedAt)));
|
||||
if (replyTo.spoilerText != null && !replyTo.spoilerText.isBlank()) {
|
||||
if (status.editedAt==null) timestamp.setText(UiUtils.formatRelativeTimestamp(getContext(), status.createdAt));
|
||||
else timestamp.setText(getString(R.string.edited_timestamp, UiUtils.formatRelativeTimestamp(getContext(), status.editedAt)));
|
||||
if (status.spoilerText != null && !status.spoilerText.isBlank()) {
|
||||
view.findViewById(R.id.spoiler_header).setVisibility(View.VISIBLE);
|
||||
((TextView) view.findViewById(R.id.spoiler_title_inline)).setText(replyTo.spoilerText);
|
||||
((TextView) view.findViewById(R.id.spoiler_title_inline)).setText(status.spoilerText);
|
||||
}
|
||||
|
||||
SpannableStringBuilder content = HtmlParser.parse(replyTo.content, replyTo.emojis, replyTo.mentions, replyTo.tags, accountID);
|
||||
SpannableStringBuilder content = HtmlParser.parse(status.content, status.emojis, status.mentions, status.tags, accountID);
|
||||
LinkedTextView text = view.findViewById(R.id.text);
|
||||
if (content.length() > 0) text.setText(content);
|
||||
else view.findViewById(R.id.display_item_text).setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, V.dp(16)));
|
||||
|
||||
replyText.setText(getString(R.string.in_reply_to, replyTo.account.displayName));
|
||||
int visibilityNameRes = switch (replyTo.visibility) {
|
||||
replyText.setText(getString(quote!=null? R.string.sk_quoting_user : R.string.in_reply_to, status.account.displayName));
|
||||
int visibilityNameRes = switch (status.visibility) {
|
||||
case PUBLIC -> R.string.visibility_public;
|
||||
case UNLISTED -> R.string.sk_visibility_unlisted;
|
||||
case PRIVATE -> R.string.visibility_followers_only;
|
||||
case DIRECT -> R.string.visibility_private;
|
||||
case LOCAL -> R.string.sk_local_only;
|
||||
};
|
||||
replyText.setContentDescription(getString(R.string.in_reply_to, replyTo.account.displayName) + ". " + getString(R.string.post_visibility) + ": " + getString(visibilityNameRes));
|
||||
replyText.setContentDescription(getString(R.string.in_reply_to, status.account.displayName) + ". " + getString(R.string.post_visibility) + ": " + getString(visibilityNameRes));
|
||||
replyText.setOnClickListener(v->{
|
||||
scrollView.smoothScrollTo(0, 0);
|
||||
});
|
||||
|
||||
ArrayList<String> mentions=new ArrayList<>();
|
||||
String ownID=AccountSessionManager.getInstance().getAccount(accountID).self.id;
|
||||
if(!replyTo.account.id.equals(ownID))
|
||||
mentions.add('@'+replyTo.account.acct);
|
||||
for(Mention mention:replyTo.mentions){
|
||||
if(!status.account.id.equals(ownID))
|
||||
mentions.add('@'+status.account.acct);
|
||||
for(Mention mention:status.mentions){
|
||||
if(mention.id.equals(ownID))
|
||||
continue;
|
||||
String m='@'+mention.acct;
|
||||
@@ -712,17 +716,17 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
ignoreSelectionChanges=true;
|
||||
mainEditText.setSelection(mainEditText.length());
|
||||
ignoreSelectionChanges=false;
|
||||
if(!TextUtils.isEmpty(replyTo.spoilerText)){
|
||||
if(!TextUtils.isEmpty(status.spoilerText)){
|
||||
hasSpoiler=true;
|
||||
spoilerEdit.setVisibility(View.VISIBLE);
|
||||
if(GlobalUserPreferences.prefixRepliesWithRe && !replyTo.spoilerText.startsWith("re: ")){
|
||||
spoilerEdit.setText("re: " + replyTo.spoilerText);
|
||||
if(GlobalUserPreferences.prefixRepliesWithRe && !status.spoilerText.startsWith("re: ")){
|
||||
spoilerEdit.setText("re: " + status.spoilerText);
|
||||
}else{
|
||||
spoilerEdit.setText(replyTo.spoilerText);
|
||||
spoilerEdit.setText(status.spoilerText);
|
||||
}
|
||||
spoilerBtn.setSelected(true);
|
||||
}
|
||||
if (replyTo.language != null && !replyTo.language.isEmpty()) updateLanguage(replyTo.language);
|
||||
if (status.language != null && !status.language.isEmpty()) updateLanguage(status.language);
|
||||
}
|
||||
}else if (editingStatus==null || editingStatus.inReplyToId==null){
|
||||
// TODO: remove workaround after https://github.com/mastodon/mastodon-android/issues/341 gets fixed
|
||||
@@ -1089,6 +1093,9 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
if(hasSpoiler && spoilerEdit.length()>0){
|
||||
req.spoilerText=spoilerEdit.getText().toString();
|
||||
}
|
||||
if(quote != null){
|
||||
req.quoteId=quote.id;
|
||||
}
|
||||
if(uuid==null)
|
||||
uuid=UUID.randomUUID().toString();
|
||||
|
||||
|
||||
@@ -213,6 +213,22 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
||||
GlobalUserPreferences.showReplies=i.checked;
|
||||
GlobalUserPreferences.save();
|
||||
}));
|
||||
if (instance.pleroma != null) {
|
||||
items.add(new ButtonItem(R.string.sk_settings_reply_visibility, R.drawable.ic_fluent_chat_24_regular, b->{
|
||||
PopupMenu popupMenu=new PopupMenu(getActivity(), b, Gravity.CENTER_HORIZONTAL);
|
||||
popupMenu.inflate(R.menu.reply_visibility);
|
||||
popupMenu.setOnMenuItemClickListener(item -> this.onReplyVisibilityChanged(item, b));
|
||||
b.setOnTouchListener(popupMenu.getDragToOpenListener());
|
||||
b.setOnClickListener(v->popupMenu.show());
|
||||
b.setText(GlobalUserPreferences.replyVisibility == null ?
|
||||
R.string.sk_settings_reply_visibility_all :
|
||||
switch(GlobalUserPreferences.replyVisibility){
|
||||
case "following" -> R.string.sk_settings_reply_visibility_following;
|
||||
case "self" -> R.string.sk_settings_reply_visibility_self;
|
||||
default -> R.string.sk_settings_reply_visibility_all;
|
||||
});
|
||||
}));
|
||||
}
|
||||
items.add(new SwitchItem(R.string.sk_settings_show_boosts, R.drawable.ic_fluent_arrow_repeat_all_24_regular, GlobalUserPreferences.showBoosts, i->{
|
||||
GlobalUserPreferences.showBoosts=i.checked;
|
||||
GlobalUserPreferences.save();
|
||||
@@ -480,6 +496,25 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
||||
}
|
||||
}
|
||||
|
||||
private boolean onReplyVisibilityChanged(MenuItem item, Button btn){
|
||||
String pref = null;
|
||||
int id = item.getItemId();
|
||||
|
||||
if (id == R.id.reply_visibility_following) pref = "following";
|
||||
else if (id == R.id.reply_visibility_self) pref = "self";
|
||||
|
||||
GlobalUserPreferences.replyVisibility=pref;
|
||||
GlobalUserPreferences.save();
|
||||
btn.setText(GlobalUserPreferences.replyVisibility == null ?
|
||||
R.string.sk_settings_reply_visibility_all :
|
||||
switch(GlobalUserPreferences.replyVisibility){
|
||||
case "following" -> R.string.sk_settings_reply_visibility_following;
|
||||
case "self" -> R.string.sk_settings_reply_visibility_self;
|
||||
default -> R.string.sk_settings_reply_visibility_all;
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
private void restartActivityToApplyNewTheme(){
|
||||
// Calling activity.recreate() causes a black screen for like half a second.
|
||||
// So, let's take a screenshot and overlay it on top to create the illusion of a smoother transition.
|
||||
|
||||
@@ -5,9 +5,12 @@ import android.view.View;
|
||||
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.requests.statuses.GetStatusContext;
|
||||
import org.joinmastodon.android.api.session.AccountSession;
|
||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||
import org.joinmastodon.android.events.StatusCreatedEvent;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.model.Filter;
|
||||
import org.joinmastodon.android.model.Instance;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
import org.joinmastodon.android.model.StatusContext;
|
||||
import org.joinmastodon.android.ui.displayitems.ExtendedFooterStatusDisplayItem;
|
||||
@@ -19,6 +22,7 @@ import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
import org.joinmastodon.android.utils.StatusFilterPredicate;
|
||||
import org.parceler.Parcels;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -68,6 +72,30 @@ public class ThreadFragment extends StatusListFragment{
|
||||
data.add(mainStatus);
|
||||
onAppendItems(Collections.singletonList(mainStatus));
|
||||
}
|
||||
AccountSession account=AccountSessionManager.getInstance().getAccount(accountID);
|
||||
Instance instance=AccountSessionManager.getInstance().getInstanceInfo(account.domain);
|
||||
if(instance.pleroma != null){
|
||||
List<String> threadIds=new ArrayList<>();
|
||||
threadIds.add(mainStatus.id);
|
||||
for(Status s:result.descendants){
|
||||
if(threadIds.contains(s.inReplyToId)){
|
||||
threadIds.add(s.id);
|
||||
}
|
||||
}
|
||||
threadIds.add(mainStatus.inReplyToId);
|
||||
for(int i=result.ancestors.size()-1; i >= 0; i--){
|
||||
Status s=result.ancestors.get(i);
|
||||
if(s.inReplyToId != null && threadIds.contains(s.id)){
|
||||
threadIds.add(s.inReplyToId);
|
||||
}
|
||||
}
|
||||
|
||||
result.ancestors=result.ancestors.stream().filter(s -> threadIds.contains(s.id)).collect(Collectors.toList());
|
||||
result.descendants=getDescendantsOrdered(mainStatus.id,
|
||||
result.descendants.stream()
|
||||
.filter(s -> threadIds.contains(s.id))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
result.descendants=filterStatuses(result.descendants);
|
||||
result.ancestors=filterStatuses(result.ancestors);
|
||||
if(footerProgress!=null)
|
||||
@@ -90,6 +118,24 @@ public class ThreadFragment extends StatusListFragment{
|
||||
.exec(accountID);
|
||||
}
|
||||
|
||||
private List<Status> getDescendantsOrdered(String id, List<Status> statuses){
|
||||
List<Status> out=new ArrayList<>();
|
||||
for(Status s:getDirectDescendants(id, statuses)){
|
||||
out.add(s);
|
||||
getDirectDescendants(s.id, statuses).forEach(d ->{
|
||||
out.add(d);
|
||||
out.addAll(getDescendantsOrdered(d.id, statuses));
|
||||
});
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
private List<Status> getDirectDescendants(String id, List<Status> statuses){
|
||||
return statuses.stream()
|
||||
.filter(s -> s.inReplyToId.equals(id))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<Status> filterStatuses(List<Status> statuses){
|
||||
StatusFilterPredicate statusFilterPredicate=new StatusFilterPredicate(accountID,Filter.FilterContext.THREAD);
|
||||
return statuses.stream()
|
||||
|
||||
Reference in New Issue
Block a user