Previewing posts on Akkoma (#933)

* Previewing posts on Akkoma

* move preview property into status

* clean up code

* revert imm-related changes

---------

Co-authored-by: sk <sk22@mailbox.org>
This commit is contained in:
Jacoco
2023-11-15 15:17:29 +01:00
committed by GitHub
parent 786ce78b08
commit 6b234209c6
12 changed files with 101 additions and 31 deletions

View File

@@ -48,6 +48,8 @@ public class CreateStatus extends MastodonAPIRequest<Status>{
public String quoteId;
public ContentType contentType;
public boolean preview;
public static class Poll{
public ArrayList<String> options=new ArrayList<>();
public int expiresIn;

View File

@@ -214,7 +214,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
private BackgroundColorSpan overLimitBG;
private ForegroundColorSpan overLimitFG;
public ComposeFragment(){
super(R.layout.toolbar_fragment_with_progressbar);
}
@@ -807,25 +807,28 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
actionItem.setActionView(wrap);
actionItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
draftsBtn = wrap.findViewById(R.id.drafts_btn);
draftOptionsPopup = new PopupMenu(getContext(), draftsBtn);
draftsBtn=wrap.findViewById(R.id.drafts_btn);
draftOptionsPopup=new PopupMenu(getContext(), draftsBtn);
draftOptionsPopup.inflate(R.menu.compose_more);
draftMenuItem = draftOptionsPopup.getMenu().findItem(R.id.draft);
undraftMenuItem = draftOptionsPopup.getMenu().findItem(R.id.undraft);
scheduleMenuItem = draftOptionsPopup.getMenu().findItem(R.id.schedule);
unscheduleMenuItem = draftOptionsPopup.getMenu().findItem(R.id.unschedule);
Menu draftOptionsMenu=draftOptionsPopup.getMenu();
draftMenuItem=draftOptionsMenu.findItem(R.id.draft);
undraftMenuItem=draftOptionsMenu.findItem(R.id.undraft);
scheduleMenuItem=draftOptionsMenu.findItem(R.id.schedule);
unscheduleMenuItem=draftOptionsMenu.findItem(R.id.unschedule);
draftOptionsMenu.findItem(R.id.preview).setVisible(isInstanceAkkoma());
draftOptionsPopup.setOnMenuItemClickListener(i->{
int id = i.getItemId();
if (id == R.id.draft) updateScheduledAt(getDraftInstant());
else if (id == R.id.schedule) pickScheduledDateTime();
else if (id == R.id.unschedule || id == R.id.undraft) updateScheduledAt(null);
else navigateToUnsentPosts();
int id=i.getItemId();
if(id==R.id.draft) updateScheduledAt(getDraftInstant());
else if(id==R.id.schedule) pickScheduledDateTime();
else if(id==R.id.unschedule || id==R.id.undraft) updateScheduledAt(null);
else if(id==R.id.drafts) navigateToUnsentPosts();
else if(id==R.id.preview) publish(true);
return true;
});
UiUtils.enablePopupMenuIcons(getContext(), draftOptionsPopup);
publishButton = wrap.findViewById(R.id.publish_btn);
languageButton = wrap.findViewById(R.id.language_btn);
publishButton=wrap.findViewById(R.id.publish_btn);
languageButton=wrap.findViewById(R.id.language_btn);
languageButton.setOnClickListener(v->showLanguageAlert());
languageButton.setOnLongClickListener(v->{
if(!getLocalPrefs().bottomEncoding){
@@ -1051,6 +1054,10 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
}
private void publish(){
publish(false);
}
private void publish(boolean preview){
sendingOverlay=new View(getActivity());
WindowManager.LayoutParams overlayParams=new WindowManager.LayoutParams();
overlayParams.type=WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
@@ -1064,10 +1071,12 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
publishButton.setEnabled(false);
V.setVisibilityAnimated(sendProgress, View.VISIBLE);
mediaViewController.saveAltTextsBeforePublishing(this::actuallyPublish, this::handlePublishError);
mediaViewController.saveAltTextsBeforePublishing(
()->actuallyPublish(preview),
this::handlePublishError);
}
private void actuallyPublish(){
private void actuallyPublish(boolean preview){
String text=mainEditText.getText().toString();
CreateStatus.Request req=new CreateStatus.Request();
if("bottom".equals(postLang.encoding)){
@@ -1085,6 +1094,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
req.sensitive=sensitive;
req.contentType=contentType==ContentType.UNSPECIFIED ? null : contentType;
req.scheduledAt=scheduledAt;
req.preview=preview;
if(!mediaViewController.isEmpty()){
req.mediaIds=mediaViewController.getAttachmentIDs();
if(editingStatus != null){
@@ -1112,7 +1122,12 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
Callback<Status> resCallback=new Callback<>(){
@Override
public void onSuccess(Status result){
maybeDeleteScheduledPost(() -> {
if(preview){
openPreview(result);
return;
}
maybeDeleteScheduledPost(()->{
wm.removeView(sendingOverlay);
sendingOverlay=null;
if(editingStatus==null || redraftStatus){
@@ -1134,10 +1149,10 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
}
E.post(new StatusUpdatedEvent(editedStatus));
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O || !isStateSaved()) {
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.O || !isStateSaved()){
Nav.finish(ComposeFragment.this);
}
if (getArguments().getBoolean("navigateToStatus", false)) {
if(getArguments().getBoolean("navigateToStatus", false)){
Bundle args=new Bundle();
args.putString("account", accountID);
args.putParcelable("status", Parcels.wrap(result));
@@ -1153,11 +1168,11 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
}
};
if(editingStatus!=null && !redraftStatus){
if(editingStatus!=null && !redraftStatus && !preview){
new EditStatus(req, editingStatus.id)
.setCallback(resCallback)
.exec(accountID);
}else if(req.scheduledAt == null){
}else if(req.scheduledAt == null || preview){
new CreateStatus(req, uuid)
.setCallback(resCallback)
.exec(accountID);
@@ -1210,6 +1225,25 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
}
}
private void openPreview(Status result){
result.preview=true;
wm.removeView(sendingOverlay);
sendingOverlay=null;
publishButton.setEnabled(true);
V.setVisibilityAnimated(sendProgress, View.GONE);
InputMethodManager imm=getActivity().getSystemService(InputMethodManager.class);
imm.hideSoftInputFromWindow(contentView.getWindowToken(), 0);
Bundle args=new Bundle();
args.putString("account", accountID);
args.putParcelable("status", Parcels.wrap(result));
if(replyTo!=null){
args.putParcelable("inReplyTo", Parcels.wrap(replyTo));
args.putParcelable("inReplyToAccount", Parcels.wrap(replyTo.account));
}
Nav.go(getActivity(), ThreadFragment.class, args);
}
private void updateRecentLanguages() {
if (postLang == null || postLang.language == null) return;
String language = postLang.language.getLanguage();
@@ -1528,6 +1562,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
}
contentTypePopup.setOnMenuItemClickListener(i->{
uuid=null;
int index=i.getItemId();
contentType=ContentType.values()[index];
btn.setSelected(index!=ContentType.UNSPECIFIED.ordinal() && index!=ContentType.PLAIN.ordinal());

View File

@@ -84,8 +84,7 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>
@Override
public void onItemClick(String id){
Status status=getContentStatusByID(id);
if(status==null)
return;
if(status==null || status.preview) return;
status.filterRevealed=true;
Bundle args=new Bundle();
args.putString("account", accountID);

View File

@@ -50,22 +50,25 @@ import me.grishka.appkit.api.SimpleCallback;
import me.grishka.appkit.utils.V;
public class ThreadFragment extends StatusListFragment implements ProvidesAssistContent {
protected Status mainStatus, updatedStatus;
protected Status mainStatus, updatedStatus, replyTo;
private final HashMap<String, NeighborAncestryInfo> ancestryMap = new HashMap<>();
private StatusContext result;
protected boolean contextInitiallyRendered, transitionFinished;
protected boolean contextInitiallyRendered, transitionFinished, preview;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
mainStatus=Parcels.unwrap(getArguments().getParcelable("status"));
replyTo=Parcels.unwrap(getArguments().getParcelable("inReplyTo"));
Account inReplyToAccount=Parcels.unwrap(getArguments().getParcelable("inReplyToAccount"));
refreshing=contextInitiallyRendered=getArguments().getBoolean("refresh", false);
if(inReplyToAccount!=null)
knownAccounts.put(inReplyToAccount.id, inReplyToAccount);
data.add(mainStatus);
onAppendItems(Collections.singletonList(mainStatus));
setTitle(HtmlParser.parseCustomEmoji(getString(R.string.post_from_user, mainStatus.account.getDisplayName()), mainStatus.account.emojis));
preview=mainStatus.preview;
if(preview) setRefreshEnabled(false);
setTitle(preview ? getString(R.string.sk_post_preview) : HtmlParser.parseCustomEmoji(getString(R.string.post_from_user, mainStatus.account.getDisplayName()), mainStatus.account.emojis));
transitionFinished = getArguments().getBoolean("noTransition", false);
}
@@ -130,11 +133,21 @@ public class ThreadFragment extends StatusListFragment implements ProvidesAssist
@Override
protected void doLoadData(int offset, int count){
if (refreshing) loadMainStatus();
currentRequest=new GetStatusContext(mainStatus.id)
if(preview && replyTo==null){
result=new StatusContext();
result.descendants=Collections.emptyList();
result.ancestors=Collections.emptyList();
return;
}
if(refreshing && !preview) loadMainStatus();
currentRequest=new GetStatusContext(preview ? replyTo.id : mainStatus.id)
.setCallback(new SimpleCallback<>(this){
@Override
public void onSuccess(StatusContext result){
if(preview){
result.descendants=Collections.emptyList();
result.ancestors.add(replyTo);
}
ThreadFragment.this.result = result;
maybeApplyContext();
}

View File

@@ -97,6 +97,7 @@ public class Status extends BaseModel implements DisplayItemsParent, Searchable{
public transient TranslationState translationState=TranslationState.HIDDEN;
public transient Translation translation;
public transient boolean fromStatusCreated;
public transient boolean preview;
public Status(){}

View File

@@ -129,6 +129,7 @@ public class ExtendedFooterStatusDisplayItem extends StatusDisplayItem{
}
private void startAccountListFragment(Class<? extends StatusRelatedAccountListFragment> cls){
if(item.status.preview) return;
Bundle args=new Bundle();
args.putString("account", item.parentFragment.getAccountID());
args.putParcelable("status", Parcels.wrap(item.status));
@@ -136,6 +137,7 @@ public class ExtendedFooterStatusDisplayItem extends StatusDisplayItem{
}
private void startEditHistoryFragment(){
if(item.status.preview) return;
Bundle args=new Bundle();
args.putString("account", item.parentFragment.getAccountID());
args.putString("id", item.status.id);

View File

@@ -158,6 +158,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
}
private boolean onButtonTouch(View v, MotionEvent event){
if(item.status.preview) return false;
boolean disabled = !v.isEnabled() || (v instanceof FrameLayout parentFrame &&
parentFrame.getChildCount() > 0 && !parentFrame.getChildAt(0).isEnabled());
int action = event.getAction();
@@ -180,6 +181,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
}
private void onReplyClick(View v){
if(item.status.preview) return;
UiUtils.opacityIn(v);
Bundle args=new Bundle();
args.putString("account", item.accountID);
@@ -188,6 +190,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
}
private boolean onReplyLongClick(View v) {
if(item.status.preview) return false;
if (AccountSessionManager.getInstance().getLoggedInAccounts().size() < 2) return false;
UiUtils.pickAccount(v.getContext(), item.accountID, R.string.sk_reply_as, R.drawable.ic_fluent_arrow_reply_28_regular, session -> {
Bundle args=new Bundle();
@@ -203,6 +206,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
}
private void onBoostClick(View v){
if(item.status.preview) return;
if (GlobalUserPreferences.confirmBoost) {
UiUtils.opacityIn(v);
onBoostLongClick(v);
@@ -218,6 +222,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
}
private boolean onBoostLongClick(View v){
if(item.status.preview) return false;
Context ctx = itemView.getContext();
View menu = LayoutInflater.from(ctx).inflate(R.layout.item_boost_menu, null);
Dialog dialog = new M3AlertDialogBuilder(ctx).setView(menu).create();
@@ -300,6 +305,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
}
private void onFavoriteClick(View v){
if(item.status.preview) return;
favorite.setSelected(!item.status.favourited);
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setFavorited(item.status, !item.status.favourited, r->{
UiUtils.opacityIn(v);
@@ -308,6 +314,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
}
private boolean onFavoriteLongClick(View v) {
if(item.status.preview) return false;
if (AccountSessionManager.getInstance().getLoggedInAccounts().size() < 2) return false;
UiUtils.pickInteractAs(v.getContext(),
item.accountID, item.status,
@@ -322,6 +329,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
}
private void onBookmarkClick(View v){
if(item.status.preview) return;
bookmark.setSelected(!item.status.bookmarked);
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setBookmarked(item.status, !item.status.bookmarked, r->{
UiUtils.opacityIn(v);
@@ -329,6 +337,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
}
private boolean onBookmarkLongClick(View v) {
if(item.status.preview) return false;
if (AccountSessionManager.getInstance().getLoggedInAccounts().size() < 2) return false;
UiUtils.pickInteractAs(v.getContext(),
item.accountID, item.status,
@@ -343,6 +352,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
}
private void onShareClick(View v){
if(item.status.preview) return;
UiUtils.opacityIn(v);
Intent intent=new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
@@ -351,6 +361,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
}
private boolean onShareLongClick(View v){
if(item.status.preview) return false;
UiUtils.copyText(v, item.status.url);
return true;
}

View File

@@ -445,6 +445,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
}
private void onMoreClick(View v){
if(item.status.preview) return;
updateOptionsMenu();
optionsMenu.show();
if(relationship==null && currentRelationshipRequest==null){

View File

@@ -76,7 +76,7 @@ public abstract class StatusDisplayItem{
public static final int FLAG_NO_TRANSLATE=1 << 5;
public static final int FLAG_NO_EMOJI_REACTIONS=1 << 6;
public static final int FLAG_IS_FOR_QUOTE=1 << 7;
public void setAncestryInfo(
boolean hasDescendantNeighbor,
boolean hasAncestoringNeighbor,
@@ -166,7 +166,7 @@ public abstract class StatusDisplayItem{
HeaderStatusDisplayItem header=null;
boolean hideCounts=!AccountSessionManager.get(accountID).getLocalPreferences().showInteractionCounts;
if((flags & FLAG_NO_HEADER)==0){
ReblogOrReplyLineStatusDisplayItem replyLine = null;
boolean threadReply = statusForContent.inReplyToAccountId != null &&
@@ -305,7 +305,7 @@ public abstract class StatusDisplayItem{
items.addAll(contentItems);
}
AccountLocalPreferences lp=fragment.getLocalPrefs();
if((flags & FLAG_NO_EMOJI_REACTIONS)==0 && lp.emojiReactionsEnabled &&
if((flags & FLAG_NO_EMOJI_REACTIONS)==0 && !status.preview && lp.emojiReactionsEnabled &&
(lp.showEmojiReactions!=ONLY_OPENED || fragment instanceof ThreadFragment) &&
statusForContent.reactions!=null){
boolean isMainStatus=fragment instanceof ThreadFragment t && t.getMainStatus().id.equals(statusForContent.id);