Polls in compose
This commit is contained in:
parent
dc63d054dc
commit
ce258f1b54
|
@ -14,7 +14,6 @@ import android.os.Bundle;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
import android.util.Log;
|
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
|
@ -30,6 +29,7 @@ import android.widget.FrameLayout;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.PopupMenu;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
@ -50,11 +50,14 @@ import org.joinmastodon.android.model.Attachment;
|
||||||
import org.joinmastodon.android.model.Emoji;
|
import org.joinmastodon.android.model.Emoji;
|
||||||
import org.joinmastodon.android.model.EmojiCategory;
|
import org.joinmastodon.android.model.EmojiCategory;
|
||||||
import org.joinmastodon.android.model.Mention;
|
import org.joinmastodon.android.model.Mention;
|
||||||
|
import org.joinmastodon.android.model.Poll;
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
import org.joinmastodon.android.ui.CustomEmojiPopupKeyboard;
|
import org.joinmastodon.android.ui.CustomEmojiPopupKeyboard;
|
||||||
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
||||||
import org.joinmastodon.android.ui.PopupKeyboard;
|
import org.joinmastodon.android.ui.PopupKeyboard;
|
||||||
import org.joinmastodon.android.ui.text.HtmlParser;
|
import org.joinmastodon.android.ui.text.HtmlParser;
|
||||||
|
import org.joinmastodon.android.ui.utils.SimpleTextWatcher;
|
||||||
|
import org.joinmastodon.android.ui.views.ReorderableLinearLayout;
|
||||||
import org.joinmastodon.android.ui.views.SizeListenerLinearLayout;
|
import org.joinmastodon.android.ui.views.SizeListenerLinearLayout;
|
||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
|
@ -76,6 +79,7 @@ import me.grishka.appkit.utils.V;
|
||||||
public class ComposeFragment extends ToolbarFragment implements OnBackPressedListener{
|
public class ComposeFragment extends ToolbarFragment implements OnBackPressedListener{
|
||||||
|
|
||||||
private static final int MEDIA_RESULT=717;
|
private static final int MEDIA_RESULT=717;
|
||||||
|
private static final int MAX_POLL_OPTIONS=4;
|
||||||
|
|
||||||
private static final Pattern MENTION_PATTERN=Pattern.compile("(^|[^\\/\\w])@(([a-z0-9_]+)@[a-z0-9\\.\\-]+[a-z0-9]+)", Pattern.CASE_INSENSITIVE);
|
private static final Pattern MENTION_PATTERN=Pattern.compile("(^|[^\\/\\w])@(([a-z0-9_]+)@[a-z0-9\\.\\-]+[a-z0-9]+)", Pattern.CASE_INSENSITIVE);
|
||||||
|
|
||||||
|
@ -112,6 +116,12 @@ public class ComposeFragment extends ToolbarFragment implements OnBackPressedLis
|
||||||
private ImageButton mediaBtn, pollBtn, emojiBtn, spoilerBtn, visibilityBtn;
|
private ImageButton mediaBtn, pollBtn, emojiBtn, spoilerBtn, visibilityBtn;
|
||||||
private LinearLayout attachmentsView;
|
private LinearLayout attachmentsView;
|
||||||
private TextView replyText;
|
private TextView replyText;
|
||||||
|
private ReorderableLinearLayout pollOptionsView;
|
||||||
|
private View pollWrap;
|
||||||
|
private View addPollOptionBtn;
|
||||||
|
private TextView pollDurationView;
|
||||||
|
|
||||||
|
private ArrayList<DraftPollOption> pollOptions=new ArrayList<>();
|
||||||
|
|
||||||
private ArrayList<DraftMediaAttachment> queuedAttachments=new ArrayList<>(), failedAttachments=new ArrayList<>(), attachments=new ArrayList<>();
|
private ArrayList<DraftMediaAttachment> queuedAttachments=new ArrayList<>(), failedAttachments=new ArrayList<>(), attachments=new ArrayList<>();
|
||||||
private DraftMediaAttachment uploadingAttachment;
|
private DraftMediaAttachment uploadingAttachment;
|
||||||
|
@ -121,6 +131,7 @@ public class ComposeFragment extends ToolbarFragment implements OnBackPressedLis
|
||||||
private Status replyTo;
|
private Status replyTo;
|
||||||
private String initialReplyMentions;
|
private String initialReplyMentions;
|
||||||
private String uuid;
|
private String uuid;
|
||||||
|
private int pollDuration=24*3600;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(Activity activity){
|
public void onAttach(Activity activity){
|
||||||
|
@ -171,6 +182,7 @@ public class ComposeFragment extends ToolbarFragment implements OnBackPressedLis
|
||||||
replyText=view.findViewById(R.id.reply_text);
|
replyText=view.findViewById(R.id.reply_text);
|
||||||
|
|
||||||
mediaBtn.setOnClickListener(v->openFilePicker());
|
mediaBtn.setOnClickListener(v->openFilePicker());
|
||||||
|
pollBtn.setOnClickListener(v->togglePoll());
|
||||||
emojiBtn.setOnClickListener(v->emojiKeyboard.toggleKeyboardPopup(mainEditText));
|
emojiBtn.setOnClickListener(v->emojiKeyboard.toggleKeyboardPopup(mainEditText));
|
||||||
emojiKeyboard.setOnIconChangedListener(new PopupKeyboard.OnIconChangeListener(){
|
emojiKeyboard.setOnIconChangedListener(new PopupKeyboard.OnIconChangeListener(){
|
||||||
@Override
|
@Override
|
||||||
|
@ -184,6 +196,18 @@ public class ComposeFragment extends ToolbarFragment implements OnBackPressedLis
|
||||||
emojiKeyboard.getView().setElevation(V.dp(2));
|
emojiKeyboard.getView().setElevation(V.dp(2));
|
||||||
|
|
||||||
attachmentsView=view.findViewById(R.id.attachments);
|
attachmentsView=view.findViewById(R.id.attachments);
|
||||||
|
pollOptionsView=view.findViewById(R.id.poll_options);
|
||||||
|
pollWrap=view.findViewById(R.id.poll_wrap);
|
||||||
|
addPollOptionBtn=view.findViewById(R.id.add_poll_option);
|
||||||
|
|
||||||
|
addPollOptionBtn.setOnClickListener(v->{
|
||||||
|
createDraftPollOption().edit.requestFocus();
|
||||||
|
updatePollOptionHints();
|
||||||
|
});
|
||||||
|
pollOptionsView.setDragListener(this::onSwapPollOptions);
|
||||||
|
pollDurationView=view.findViewById(R.id.poll_duration);
|
||||||
|
pollDurationView.setText(getString(R.string.compose_poll_duration, getResources().getQuantityString(R.plurals.x_days, 1, 1)));
|
||||||
|
pollDurationView.setOnClickListener(v->showPollDurationMenu());
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
@ -286,7 +310,13 @@ public class ComposeFragment extends ToolbarFragment implements OnBackPressedLis
|
||||||
|
|
||||||
private void updatePublishButtonState(){
|
private void updatePublishButtonState(){
|
||||||
uuid=null;
|
uuid=null;
|
||||||
publishButton.setEnabled((trimmedCharCount>0 || !attachments.isEmpty()) && charCount<=charLimit && uploadingAttachment==null && failedAttachments.isEmpty() && queuedAttachments.isEmpty());
|
int nonEmptyPollOptionsCount=0;
|
||||||
|
for(DraftPollOption opt:pollOptions){
|
||||||
|
if(opt.edit.length()>0)
|
||||||
|
nonEmptyPollOptionsCount++;
|
||||||
|
}
|
||||||
|
publishButton.setEnabled((trimmedCharCount>0 || !attachments.isEmpty()) && charCount<=charLimit && uploadingAttachment==null && failedAttachments.isEmpty() && queuedAttachments.isEmpty()
|
||||||
|
&& (pollOptions.isEmpty() || nonEmptyPollOptionsCount>1));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onCustomEmojiClick(Emoji emoji){
|
private void onCustomEmojiClick(Emoji emoji){
|
||||||
|
@ -311,6 +341,12 @@ public class ComposeFragment extends ToolbarFragment implements OnBackPressedLis
|
||||||
if(replyTo!=null){
|
if(replyTo!=null){
|
||||||
req.inReplyToId=replyTo.id;
|
req.inReplyToId=replyTo.id;
|
||||||
}
|
}
|
||||||
|
if(!pollOptions.isEmpty()){
|
||||||
|
req.poll=new CreateStatus.Request.Poll();
|
||||||
|
req.poll.expiresIn=pollDuration;
|
||||||
|
for(DraftPollOption opt:pollOptions)
|
||||||
|
req.poll.options.add(opt.edit.getText().toString());
|
||||||
|
}
|
||||||
if(uuid==null)
|
if(uuid==null)
|
||||||
uuid=UUID.randomUUID().toString();
|
uuid=UUID.randomUUID().toString();
|
||||||
ProgressDialog progress=new ProgressDialog(getActivity());
|
ProgressDialog progress=new ProgressDialog(getActivity());
|
||||||
|
@ -324,8 +360,10 @@ public class ComposeFragment extends ToolbarFragment implements OnBackPressedLis
|
||||||
progress.dismiss();
|
progress.dismiss();
|
||||||
Nav.finish(ComposeFragment.this);
|
Nav.finish(ComposeFragment.this);
|
||||||
E.post(new StatusCreatedEvent(result));
|
E.post(new StatusCreatedEvent(result));
|
||||||
replyTo.repliesCount++;
|
if(replyTo!=null){
|
||||||
E.post(new StatusCountersUpdatedEvent(replyTo));
|
replyTo.repliesCount++;
|
||||||
|
E.post(new StatusCountersUpdatedEvent(replyTo));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -338,8 +376,11 @@ public class ComposeFragment extends ToolbarFragment implements OnBackPressedLis
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasDraft(){
|
private boolean hasDraft(){
|
||||||
|
boolean pollFieldsHaveContent=false;
|
||||||
|
for(DraftPollOption opt:pollOptions)
|
||||||
|
pollFieldsHaveContent|=opt.edit.length()>0;
|
||||||
return (mainEditText.length()>0 && !mainEditText.getText().toString().equals(initialReplyMentions)) || !attachments.isEmpty()
|
return (mainEditText.length()>0 && !mainEditText.getText().toString().equals(initialReplyMentions)) || !attachments.isEmpty()
|
||||||
|| uploadingAttachment!=null || !queuedAttachments.isEmpty() || !failedAttachments.isEmpty();
|
|| uploadingAttachment!=null || !queuedAttachments.isEmpty() || !failedAttachments.isEmpty() || pollFieldsHaveContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -397,6 +438,7 @@ public class ComposeFragment extends ToolbarFragment implements OnBackPressedLis
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addMediaAttachment(Uri uri){
|
private void addMediaAttachment(Uri uri){
|
||||||
|
pollBtn.setEnabled(false);
|
||||||
View thumb=getActivity().getLayoutInflater().inflate(R.layout.compose_media_thumb, attachmentsView, false);
|
View thumb=getActivity().getLayoutInflater().inflate(R.layout.compose_media_thumb, attachmentsView, false);
|
||||||
ImageView img=thumb.findViewById(R.id.thumb);
|
ImageView img=thumb.findViewById(R.id.thumb);
|
||||||
ViewImageLoader.load(img, null, new UrlImageLoaderRequest(uri, V.dp(250), V.dp(250)));
|
ViewImageLoader.load(img, null, new UrlImageLoaderRequest(uri, V.dp(250), V.dp(250)));
|
||||||
|
@ -467,6 +509,8 @@ public class ComposeFragment extends ToolbarFragment implements OnBackPressedLis
|
||||||
att.uploadRequest.cancel();
|
att.uploadRequest.cancel();
|
||||||
if(!queuedAttachments.isEmpty())
|
if(!queuedAttachments.isEmpty())
|
||||||
uploadMediaAttachment(queuedAttachments.remove(0));
|
uploadMediaAttachment(queuedAttachments.remove(0));
|
||||||
|
else
|
||||||
|
uploadingAttachment=null;
|
||||||
}else{
|
}else{
|
||||||
attachments.remove(att);
|
attachments.remove(att);
|
||||||
queuedAttachments.remove(att);
|
queuedAttachments.remove(att);
|
||||||
|
@ -474,6 +518,84 @@ public class ComposeFragment extends ToolbarFragment implements OnBackPressedLis
|
||||||
}
|
}
|
||||||
attachmentsView.removeView(att.view);
|
attachmentsView.removeView(att.view);
|
||||||
updatePublishButtonState();
|
updatePublishButtonState();
|
||||||
|
pollBtn.setEnabled(attachments.isEmpty() && queuedAttachments.isEmpty() && failedAttachments.isEmpty() && uploadingAttachment==null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void togglePoll(){
|
||||||
|
if(pollOptions.isEmpty()){
|
||||||
|
pollBtn.setSelected(true);
|
||||||
|
mediaBtn.setEnabled(false);
|
||||||
|
pollWrap.setVisibility(View.VISIBLE);
|
||||||
|
for(int i=0;i<2;i++)
|
||||||
|
createDraftPollOption();
|
||||||
|
updatePollOptionHints();
|
||||||
|
}else{
|
||||||
|
pollBtn.setSelected(false);
|
||||||
|
mediaBtn.setEnabled(true);
|
||||||
|
pollWrap.setVisibility(View.GONE);
|
||||||
|
addPollOptionBtn.setVisibility(View.VISIBLE);
|
||||||
|
pollOptionsView.removeAllViews();
|
||||||
|
pollOptions.clear();
|
||||||
|
pollDuration=24*3600;
|
||||||
|
}
|
||||||
|
updatePublishButtonState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private DraftPollOption createDraftPollOption(){
|
||||||
|
DraftPollOption option=new DraftPollOption();
|
||||||
|
option.view=LayoutInflater.from(getActivity()).inflate(R.layout.compose_poll_option, pollOptionsView, false);
|
||||||
|
option.edit=option.view.findViewById(R.id.edit);
|
||||||
|
option.dragger=option.view.findViewById(R.id.dragger_thingy);
|
||||||
|
|
||||||
|
option.dragger.setOnLongClickListener(v->{
|
||||||
|
pollOptionsView.startDragging(option.view);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
option.edit.addTextChangedListener(new SimpleTextWatcher(e->updatePublishButtonState()));
|
||||||
|
|
||||||
|
pollOptionsView.addView(option.view);
|
||||||
|
pollOptions.add(option);
|
||||||
|
if(pollOptions.size()==MAX_POLL_OPTIONS)
|
||||||
|
addPollOptionBtn.setVisibility(View.GONE);
|
||||||
|
return option;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updatePollOptionHints(){
|
||||||
|
int i=0;
|
||||||
|
for(DraftPollOption option:pollOptions){
|
||||||
|
option.edit.setHint(getString(R.string.poll_option_hint, ++i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onSwapPollOptions(int oldIndex, int newIndex){
|
||||||
|
pollOptions.add(newIndex, pollOptions.remove(oldIndex));
|
||||||
|
updatePollOptionHints();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showPollDurationMenu(){
|
||||||
|
PopupMenu menu=new PopupMenu(getActivity(), pollDurationView);
|
||||||
|
menu.getMenu().add(0, 1, 0, getResources().getQuantityString(R.plurals.x_minutes, 5, 5));
|
||||||
|
menu.getMenu().add(0, 2, 0, getResources().getQuantityString(R.plurals.x_minutes, 30, 30));
|
||||||
|
menu.getMenu().add(0, 3, 0, getResources().getQuantityString(R.plurals.x_hours, 1, 1));
|
||||||
|
menu.getMenu().add(0, 4, 0, getResources().getQuantityString(R.plurals.x_hours, 6, 6));
|
||||||
|
menu.getMenu().add(0, 5, 0, getResources().getQuantityString(R.plurals.x_days, 1, 1));
|
||||||
|
menu.getMenu().add(0, 6, 0, getResources().getQuantityString(R.plurals.x_days, 3, 3));
|
||||||
|
menu.getMenu().add(0, 7, 0, getResources().getQuantityString(R.plurals.x_days, 7, 7));
|
||||||
|
menu.setOnMenuItemClickListener(item->{
|
||||||
|
pollDuration=switch(item.getItemId()){
|
||||||
|
case 1 -> 5*60;
|
||||||
|
case 2 -> 30*60;
|
||||||
|
case 3 -> 3600;
|
||||||
|
case 4 -> 6*3600;
|
||||||
|
case 5 -> 24*3600;
|
||||||
|
case 6 -> 3*24*3600;
|
||||||
|
case 7 -> 7*24*3600;
|
||||||
|
default -> throw new IllegalStateException("Unexpected value: "+item.getItemId());
|
||||||
|
};
|
||||||
|
pollDurationView.setText(getString(R.string.compose_poll_duration, item.getTitle()));
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
menu.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class DraftMediaAttachment{
|
private static class DraftMediaAttachment{
|
||||||
|
@ -484,4 +606,10 @@ public class ComposeFragment extends ToolbarFragment implements OnBackPressedLis
|
||||||
public View view;
|
public View view;
|
||||||
public ProgressBar progressBar;
|
public ProgressBar progressBar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class DraftPollOption{
|
||||||
|
public EditText edit;
|
||||||
|
public View view;
|
||||||
|
public View dragger;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
package org.joinmastodon.android.ui.views;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewTreeObserver;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import me.grishka.appkit.utils.CubicBezierInterpolator;
|
||||||
|
import me.grishka.appkit.utils.V;
|
||||||
|
|
||||||
|
public class ReorderableLinearLayout extends LinearLayout{
|
||||||
|
private static final String TAG="ReorderableLinearLayout";
|
||||||
|
|
||||||
|
private View draggedView;
|
||||||
|
private View bottomSibling, topSibling;
|
||||||
|
private float startY;
|
||||||
|
private OnDragListener dragListener;
|
||||||
|
|
||||||
|
public ReorderableLinearLayout(Context context){
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReorderableLinearLayout(Context context, @Nullable AttributeSet attrs){
|
||||||
|
super(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReorderableLinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr){
|
||||||
|
super(context, attrs, defStyleAttr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startDragging(View child){
|
||||||
|
getParent().requestDisallowInterceptTouchEvent(true);
|
||||||
|
draggedView=child;
|
||||||
|
draggedView.animate().translationZ(V.dp(1f)).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start();
|
||||||
|
|
||||||
|
int index=indexOfChild(child);
|
||||||
|
if(index==-1)
|
||||||
|
throw new IllegalArgumentException("view "+child+" is not a child of this layout");
|
||||||
|
if(index>0)
|
||||||
|
topSibling=getChildAt(index-1);
|
||||||
|
if(index<getChildCount()-1)
|
||||||
|
bottomSibling=getChildAt(index+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onInterceptTouchEvent(MotionEvent ev){
|
||||||
|
if(draggedView!=null){
|
||||||
|
startY=ev.getY();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTouchEvent(MotionEvent ev){
|
||||||
|
if(draggedView!=null){
|
||||||
|
if(ev.getAction()==MotionEvent.ACTION_UP || ev.getAction()==MotionEvent.ACTION_CANCEL){
|
||||||
|
endDrag();
|
||||||
|
draggedView=null;
|
||||||
|
bottomSibling=null;
|
||||||
|
topSibling=null;
|
||||||
|
}else if(ev.getAction()==MotionEvent.ACTION_MOVE){
|
||||||
|
draggedView.setTranslationY(ev.getY()-startY);
|
||||||
|
if(topSibling!=null && draggedView.getY()<=topSibling.getY()){
|
||||||
|
moveDraggedView(-1);
|
||||||
|
}else if(bottomSibling!=null && draggedView.getY()>=bottomSibling.getY()){
|
||||||
|
moveDraggedView(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.onTouchEvent(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void endDrag(){
|
||||||
|
draggedView.animate().translationY(0f).translationZ(0f).setDuration(200).setInterpolator(CubicBezierInterpolator.DEFAULT).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void moveDraggedView(int positionOffset){
|
||||||
|
int index=indexOfChild(draggedView);
|
||||||
|
int prevTop=draggedView.getTop();
|
||||||
|
removeView(draggedView);
|
||||||
|
int prevIndex=index;
|
||||||
|
index+=positionOffset;
|
||||||
|
addView(draggedView, index);
|
||||||
|
final View prevSibling=positionOffset<0 ? topSibling : bottomSibling;
|
||||||
|
int prevSiblingTop=prevSibling.getTop();
|
||||||
|
if(index>0)
|
||||||
|
topSibling=getChildAt(index-1);
|
||||||
|
else
|
||||||
|
topSibling=null;
|
||||||
|
if(index<getChildCount()-1)
|
||||||
|
bottomSibling=getChildAt(index+1);
|
||||||
|
else
|
||||||
|
bottomSibling=null;
|
||||||
|
dragListener.onSwapItems(prevIndex, index);
|
||||||
|
draggedView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener(){
|
||||||
|
@Override
|
||||||
|
public boolean onPreDraw(){
|
||||||
|
draggedView.getViewTreeObserver().removeOnPreDrawListener(this);
|
||||||
|
float offset=prevTop-draggedView.getTop();
|
||||||
|
startY-=offset;
|
||||||
|
draggedView.setTranslationY(draggedView.getTranslationY()+offset);
|
||||||
|
prevSibling.setTranslationY(prevSiblingTop-prevSibling.getTop());
|
||||||
|
prevSibling.animate().translationY(0f).setInterpolator(CubicBezierInterpolator.DEFAULT).setDuration(200).start();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDragListener(OnDragListener dragListener){
|
||||||
|
this.dragListener=dragListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface OnDragListener{
|
||||||
|
void onSwapItems(int oldIndex, int newIndex);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:color="@color/gray_800" android:alpha="0.3" android:state_enabled="false"/>
|
||||||
|
<item android:color="@color/gray_800"/>
|
||||||
|
</selector>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/gray_100"/>
|
||||||
|
<corners android:radius="10dp"/>
|
||||||
|
</shape>
|
|
@ -0,0 +1,3 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||||
|
<path android:pathData="M12 3.5c-4.694 0-8.5 3.806-8.5 8.5s3.806 8.5 8.5 8.5 8.5-3.806 8.5-8.5-3.806-8.5-8.5-8.5zM2 12C2 6.477 6.477 2 12 2s10 4.477 10 10-4.477 10-10 10S2 17.523 2 12z" android:fillColor="@color/fluent_default_icon_tint"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingBottom="8dp"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:clipToPadding="false">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@drawable/bg_poll_option"
|
||||||
|
android:outlineProvider="background"
|
||||||
|
android:elevation="2dp">
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_margin="16dp"
|
||||||
|
android:src="@drawable/ic_fluent_circle_24_regular"/>
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/edit"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@null"
|
||||||
|
android:paddingStart="0dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:textAppearance="@style/m3_title_medium"
|
||||||
|
android:inputType="textCapSentences"
|
||||||
|
android:singleLine="true"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/dragger_thingy"
|
||||||
|
android:layout_width="56dp"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
android:scaleType="center"
|
||||||
|
android:src="@drawable/ic_fluent_re_order_dots_vertical_24_regular"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
|
@ -81,6 +81,46 @@
|
||||||
android:background="@null"
|
android:background="@null"
|
||||||
android:inputType="textMultiLine|textCapSentences"/>
|
android:inputType="textMultiLine|textCapSentences"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/poll_wrap"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible">
|
||||||
|
<org.joinmastodon.android.ui.views.ReorderableLinearLayout
|
||||||
|
android:id="@+id/poll_options"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"/>
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/add_poll_option"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="56dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:background="@drawable/bg_poll_option"
|
||||||
|
android:outlineProvider="background"
|
||||||
|
android:elevation="2dp">
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_margin="16dp"
|
||||||
|
android:src="@drawable/ic_fluent_add_circle_24_regular"/>
|
||||||
|
</LinearLayout>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/poll_duration"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
|
android:layout_marginRight="16dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:textAppearance="@style/m3_label_large"
|
||||||
|
android:textColor="@color/gray_800"
|
||||||
|
tools:text="Duration: 7 days"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/attachments"
|
android:id="@+id/attachments"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -109,6 +149,8 @@
|
||||||
android:layout_marginEnd="24dp"
|
android:layout_marginEnd="24dp"
|
||||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||||
android:padding="0px"
|
android:padding="0px"
|
||||||
|
android:tint="@color/compose_button"
|
||||||
|
android:tintMode="src_in"
|
||||||
android:src="@drawable/ic_fluent_image_24_regular"/>
|
android:src="@drawable/ic_fluent_image_24_regular"/>
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
|
@ -118,6 +160,8 @@
|
||||||
android:layout_marginEnd="24dp"
|
android:layout_marginEnd="24dp"
|
||||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||||
android:padding="0px"
|
android:padding="0px"
|
||||||
|
android:tint="@color/compose_button"
|
||||||
|
android:tintMode="src_in"
|
||||||
android:src="@drawable/ic_fluent_poll_24_selector"/>
|
android:src="@drawable/ic_fluent_poll_24_selector"/>
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
|
@ -127,6 +171,8 @@
|
||||||
android:layout_marginEnd="24dp"
|
android:layout_marginEnd="24dp"
|
||||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||||
android:padding="0px"
|
android:padding="0px"
|
||||||
|
android:tint="@color/compose_button"
|
||||||
|
android:tintMode="src_in"
|
||||||
android:src="@drawable/ic_fluent_emoji_24_selector"/>
|
android:src="@drawable/ic_fluent_emoji_24_selector"/>
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
|
@ -136,6 +182,8 @@
|
||||||
android:layout_marginEnd="24dp"
|
android:layout_marginEnd="24dp"
|
||||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||||
android:padding="0px"
|
android:padding="0px"
|
||||||
|
android:tint="@color/compose_button"
|
||||||
|
android:tintMode="src_in"
|
||||||
android:src="@drawable/ic_fluent_chat_warning_24_selector"/>
|
android:src="@drawable/ic_fluent_chat_warning_24_selector"/>
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
|
@ -145,6 +193,8 @@
|
||||||
android:layout_marginEnd="24dp"
|
android:layout_marginEnd="24dp"
|
||||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||||
android:padding="0px"
|
android:padding="0px"
|
||||||
|
android:tint="@color/compose_button"
|
||||||
|
android:tintMode="src_in"
|
||||||
android:src="@drawable/ic_fluent_people_community_24_regular"/>
|
android:src="@drawable/ic_fluent_people_community_24_regular"/>
|
||||||
|
|
||||||
<Space
|
<Space
|
||||||
|
|
|
@ -73,4 +73,18 @@
|
||||||
<string name="field_content">Content</string>
|
<string name="field_content">Content</string>
|
||||||
<string name="saving">Saving…</string>
|
<string name="saving">Saving…</string>
|
||||||
<string name="post_from_user">Post from %s</string>
|
<string name="post_from_user">Post from %s</string>
|
||||||
|
<string name="poll_option_hint">Option %d</string>
|
||||||
|
<plurals name="x_minutes">
|
||||||
|
<item quantity="one">%d minute</item>
|
||||||
|
<item quantity="other">%d minutes</item>
|
||||||
|
</plurals>
|
||||||
|
<plurals name="x_hours">
|
||||||
|
<item quantity="one">%d hour</item>
|
||||||
|
<item quantity="other">%d hours</item>
|
||||||
|
</plurals>
|
||||||
|
<plurals name="x_days">
|
||||||
|
<item quantity="one">%d day</item>
|
||||||
|
<item quantity="other">%d days</item>
|
||||||
|
</plurals>
|
||||||
|
<string name="compose_poll_duration">Duration: %s</string>
|
||||||
</resources>
|
</resources>
|
|
@ -16,6 +16,7 @@
|
||||||
<item name="android:buttonStyle">@style/Widget.Mastodon.Button</item>
|
<item name="android:buttonStyle">@style/Widget.Mastodon.Button</item>
|
||||||
<item name="android:alertDialogTheme">@style/Theme.Mastodon.Dialog.Alert</item>
|
<item name="android:alertDialogTheme">@style/Theme.Mastodon.Dialog.Alert</item>
|
||||||
<item name="appkitBackDrawable">@drawable/ic_fluent_arrow_left_24_regular</item>
|
<item name="appkitBackDrawable">@drawable/ic_fluent_arrow_left_24_regular</item>
|
||||||
|
<item name="android:splitMotionEvents">false</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="Theme.Mastodon.Toolbar" parent="android:ThemeOverlay.Material.ActionBar">
|
<style name="Theme.Mastodon.Toolbar" parent="android:ThemeOverlay.Material.ActionBar">
|
||||||
|
|
Loading…
Reference in New Issue