Compose design + media upload
This commit is contained in:
parent
20d3a62747
commit
cc06715aa6
|
@ -0,0 +1,72 @@
|
||||||
|
package org.joinmastodon.android.api;
|
||||||
|
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.SystemClock;
|
||||||
|
import android.provider.OpenableColumns;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.MastodonApp;
|
||||||
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import okhttp3.MediaType;
|
||||||
|
import okhttp3.RequestBody;
|
||||||
|
import okio.Buffer;
|
||||||
|
import okio.BufferedSink;
|
||||||
|
import okio.ForwardingSink;
|
||||||
|
import okio.Okio;
|
||||||
|
import okio.Sink;
|
||||||
|
import okio.Source;
|
||||||
|
|
||||||
|
public class ContentUriRequestBody extends RequestBody{
|
||||||
|
private final Uri uri;
|
||||||
|
private final long length;
|
||||||
|
private ProgressListener progressListener;
|
||||||
|
|
||||||
|
public ContentUriRequestBody(Uri uri, ProgressListener progressListener){
|
||||||
|
this.uri=uri;
|
||||||
|
this.progressListener=progressListener;
|
||||||
|
try(Cursor cursor=MastodonApp.context.getContentResolver().query(uri, new String[]{OpenableColumns.SIZE}, null, null, null)){
|
||||||
|
cursor.moveToFirst();
|
||||||
|
length=cursor.getInt(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MediaType contentType(){
|
||||||
|
return MediaType.get(MastodonApp.context.getContentResolver().getType(uri));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long contentLength() throws IOException{
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(BufferedSink sink) throws IOException{
|
||||||
|
try(Source source=Okio.source(MastodonApp.context.getContentResolver().openInputStream(uri))){
|
||||||
|
BufferedSink wrappedSink=Okio.buffer(new CountingSink(sink));
|
||||||
|
wrappedSink.writeAll(source);
|
||||||
|
wrappedSink.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CountingSink extends ForwardingSink{
|
||||||
|
private long bytesWritten=0;
|
||||||
|
private long lastCallbackTime;
|
||||||
|
public CountingSink(Sink delegate){
|
||||||
|
super(delegate);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(Buffer source, long byteCount) throws IOException{
|
||||||
|
super.write(source, byteCount);
|
||||||
|
bytesWritten+=byteCount;
|
||||||
|
if(SystemClock.uptimeMillis()-lastCallbackTime>=100L || bytesWritten==length){
|
||||||
|
lastCallbackTime=SystemClock.uptimeMillis();
|
||||||
|
UiUtils.runOnUiThread(()->progressListener.onProgress(bytesWritten, length));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
package org.joinmastodon.android.api;
|
||||||
|
|
||||||
|
public interface ProgressListener{
|
||||||
|
void onProgress(long transferred, long total);
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
package org.joinmastodon.android.api.requests.statuses;
|
||||||
|
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.provider.OpenableColumns;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.MastodonApp;
|
||||||
|
import org.joinmastodon.android.api.ContentUriRequestBody;
|
||||||
|
import org.joinmastodon.android.api.MastodonAPIRequest;
|
||||||
|
import org.joinmastodon.android.api.ProgressListener;
|
||||||
|
import org.joinmastodon.android.model.Attachment;
|
||||||
|
|
||||||
|
import okhttp3.MultipartBody;
|
||||||
|
import okhttp3.RequestBody;
|
||||||
|
|
||||||
|
public class UploadAttachment extends MastodonAPIRequest<Attachment>{
|
||||||
|
private Uri uri;
|
||||||
|
private ProgressListener progressListener;
|
||||||
|
|
||||||
|
public UploadAttachment(Uri uri){
|
||||||
|
super(HttpMethod.POST, "/media", Attachment.class);
|
||||||
|
this.uri=uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UploadAttachment setProgressListener(ProgressListener progressListener){
|
||||||
|
this.progressListener=progressListener;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RequestBody getRequestBody(){
|
||||||
|
String fileName;
|
||||||
|
try(Cursor cursor=MastodonApp.context.getContentResolver().query(uri, new String[]{OpenableColumns.DISPLAY_NAME}, null, null, null)){
|
||||||
|
cursor.moveToFirst();
|
||||||
|
fileName=cursor.getString(0);
|
||||||
|
}
|
||||||
|
if(fileName==null)
|
||||||
|
fileName=uri.getLastPathSegment();
|
||||||
|
return new MultipartBody.Builder()
|
||||||
|
.setType(MultipartBody.FORM)
|
||||||
|
.addFormDataPart("file", fileName, new ContentUriRequestBody(uri, progressListener))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,12 +2,19 @@ package org.joinmastodon.android.fragments;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.app.ProgressDialog;
|
||||||
|
import android.content.ClipData;
|
||||||
|
import android.content.Intent;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.graphics.Outline;
|
import android.graphics.Outline;
|
||||||
import android.icu.text.BreakIterator;
|
import android.icu.text.BreakIterator;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.Gravity;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
|
@ -16,9 +23,13 @@ import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.ViewOutlineProvider;
|
import android.view.ViewOutlineProvider;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
|
import android.widget.Button;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
|
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.ProgressBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.twitter.twittertext.Regex;
|
import com.twitter.twittertext.Regex;
|
||||||
|
@ -26,31 +37,40 @@ import com.twitter.twittertext.TwitterTextEmojiRegex;
|
||||||
|
|
||||||
import org.joinmastodon.android.E;
|
import org.joinmastodon.android.E;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
|
import org.joinmastodon.android.api.ProgressListener;
|
||||||
import org.joinmastodon.android.api.requests.statuses.CreateStatus;
|
import org.joinmastodon.android.api.requests.statuses.CreateStatus;
|
||||||
|
import org.joinmastodon.android.api.requests.statuses.UploadAttachment;
|
||||||
import org.joinmastodon.android.api.session.AccountSession;
|
import org.joinmastodon.android.api.session.AccountSession;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.events.StatusCreatedEvent;
|
import org.joinmastodon.android.events.StatusCreatedEvent;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
|
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.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.PopupKeyboard;
|
import org.joinmastodon.android.ui.PopupKeyboard;
|
||||||
import org.joinmastodon.android.ui.views.SizeListenerLinearLayout;
|
import org.joinmastodon.android.ui.views.SizeListenerLinearLayout;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import me.grishka.appkit.Nav;
|
import me.grishka.appkit.Nav;
|
||||||
import me.grishka.appkit.api.Callback;
|
import me.grishka.appkit.api.Callback;
|
||||||
import me.grishka.appkit.api.ErrorResponse;
|
import me.grishka.appkit.api.ErrorResponse;
|
||||||
|
import me.grishka.appkit.fragments.OnBackPressedListener;
|
||||||
import me.grishka.appkit.fragments.ToolbarFragment;
|
import me.grishka.appkit.fragments.ToolbarFragment;
|
||||||
import me.grishka.appkit.imageloader.ViewImageLoader;
|
import me.grishka.appkit.imageloader.ViewImageLoader;
|
||||||
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
|
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
|
||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
|
|
||||||
public class ComposeFragment extends ToolbarFragment{
|
public class ComposeFragment extends ToolbarFragment implements OnBackPressedListener{
|
||||||
|
|
||||||
|
private static final int MEDIA_RESULT=717;
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
@ -81,10 +101,14 @@ public class ComposeFragment extends ToolbarFragment{
|
||||||
private EditText mainEditText;
|
private EditText mainEditText;
|
||||||
private TextView charCounter;
|
private TextView charCounter;
|
||||||
private String accountID;
|
private String accountID;
|
||||||
private int charCount, charLimit;
|
private int charCount, charLimit, trimmedCharCount;
|
||||||
|
|
||||||
private MenuItem publishButton;
|
private Button publishButton;
|
||||||
private ImageButton emojiBtn;
|
private ImageButton mediaBtn, pollBtn, emojiBtn, spoilerBtn, visibilityBtn;
|
||||||
|
private LinearLayout attachmentsView;
|
||||||
|
|
||||||
|
private ArrayList<DraftMediaAttachment> queuedAttachments=new ArrayList<>(), failedAttachments=new ArrayList<>(), attachments=new ArrayList<>();
|
||||||
|
private DraftMediaAttachment uploadingAttachment;
|
||||||
|
|
||||||
private List<EmojiCategory> customEmojis;
|
private List<EmojiCategory> customEmojis;
|
||||||
private CustomEmojiPopupKeyboard emojiKeyboard;
|
private CustomEmojiPopupKeyboard emojiKeyboard;
|
||||||
|
@ -127,7 +151,13 @@ public class ComposeFragment extends ToolbarFragment{
|
||||||
selfAvatar.setOutlineProvider(roundCornersOutline);
|
selfAvatar.setOutlineProvider(roundCornersOutline);
|
||||||
selfAvatar.setClipToOutline(true);
|
selfAvatar.setClipToOutline(true);
|
||||||
|
|
||||||
|
mediaBtn=view.findViewById(R.id.btn_media);
|
||||||
|
pollBtn=view.findViewById(R.id.btn_poll);
|
||||||
emojiBtn=view.findViewById(R.id.btn_emoji);
|
emojiBtn=view.findViewById(R.id.btn_emoji);
|
||||||
|
spoilerBtn=view.findViewById(R.id.btn_spoiler);
|
||||||
|
visibilityBtn=view.findViewById(R.id.btn_visibility);
|
||||||
|
|
||||||
|
mediaBtn.setOnClickListener(v->openFilePicker());
|
||||||
emojiBtn.setOnClickListener(v->emojiKeyboard.toggleKeyboardPopup(mainEditText));
|
emojiBtn.setOnClickListener(v->emojiKeyboard.toggleKeyboardPopup(mainEditText));
|
||||||
emojiKeyboard.setOnIconChangedListener(new PopupKeyboard.OnIconChangeListener(){
|
emojiKeyboard.setOnIconChangedListener(new PopupKeyboard.OnIconChangeListener(){
|
||||||
@Override
|
@Override
|
||||||
|
@ -138,6 +168,9 @@ public class ComposeFragment extends ToolbarFragment{
|
||||||
|
|
||||||
contentView=(SizeListenerLinearLayout) view;
|
contentView=(SizeListenerLinearLayout) view;
|
||||||
contentView.addView(emojiKeyboard.getView());
|
contentView.addView(emojiKeyboard.getView());
|
||||||
|
emojiKeyboard.getView().setElevation(V.dp(2));
|
||||||
|
|
||||||
|
attachmentsView=view.findViewById(R.id.attachments);
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
@ -173,35 +206,26 @@ public class ComposeFragment extends ToolbarFragment{
|
||||||
updateCharCounter(s);
|
updateCharCounter(s);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
updateToolbar();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){
|
||||||
publishButton=menu.add("TOOT!");
|
publishButton=new Button(getActivity());
|
||||||
publishButton.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
|
publishButton.setText(R.string.publish);
|
||||||
|
publishButton.setOnClickListener(this::onPublishClick);
|
||||||
|
FrameLayout wrap=new FrameLayout(getActivity());
|
||||||
|
wrap.addView(publishButton, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.TOP|Gravity.LEFT));
|
||||||
|
wrap.setPadding(V.dp(16), V.dp(4), V.dp(16), V.dp(8));
|
||||||
|
wrap.setClipToPadding(false);
|
||||||
|
MenuItem item=menu.add(R.string.publish);
|
||||||
|
item.setActionView(wrap);
|
||||||
|
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||||
updatePublishButtonState();
|
updatePublishButtonState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item){
|
public boolean onOptionsItemSelected(MenuItem item){
|
||||||
String text=mainEditText.getText().toString();
|
|
||||||
CreateStatus.Request req=new CreateStatus.Request();
|
|
||||||
req.status=text;
|
|
||||||
String uuid=UUID.randomUUID().toString();
|
|
||||||
new CreateStatus(req, uuid)
|
|
||||||
.setCallback(new Callback<>(){
|
|
||||||
@Override
|
|
||||||
public void onSuccess(Status result){
|
|
||||||
Nav.finish(ComposeFragment.this);
|
|
||||||
E.post(new StatusCreatedEvent(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(ErrorResponse error){
|
|
||||||
error.showToast(getActivity());
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.exec(accountID);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,6 +233,7 @@ public class ComposeFragment extends ToolbarFragment{
|
||||||
public void onConfigurationChanged(Configuration newConfig){
|
public void onConfigurationChanged(Configuration newConfig){
|
||||||
super.onConfigurationChanged(newConfig);
|
super.onConfigurationChanged(newConfig);
|
||||||
emojiKeyboard.onConfigurationChanged();
|
emojiKeyboard.onConfigurationChanged();
|
||||||
|
updateToolbar();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("NewApi")
|
@SuppressLint("NewApi")
|
||||||
|
@ -225,14 +250,200 @@ public class ComposeFragment extends ToolbarFragment{
|
||||||
}
|
}
|
||||||
|
|
||||||
charCounter.setText(String.valueOf(charLimit-charCount));
|
charCounter.setText(String.valueOf(charLimit-charCount));
|
||||||
|
trimmedCharCount=text.toString().trim().length();
|
||||||
updatePublishButtonState();
|
updatePublishButtonState();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePublishButtonState(){
|
private void updatePublishButtonState(){
|
||||||
publishButton.setEnabled(charCount>0 && charCount<=charLimit);
|
publishButton.setEnabled((trimmedCharCount>0 || !attachments.isEmpty()) && charCount<=charLimit && uploadingAttachment==null && failedAttachments.isEmpty() && queuedAttachments.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onCustomEmojiClick(Emoji emoji){
|
private void onCustomEmojiClick(Emoji emoji){
|
||||||
mainEditText.getText().replace(mainEditText.getSelectionStart(), mainEditText.getSelectionEnd(), ':'+emoji.shortcode+':');
|
mainEditText.getText().replace(mainEditText.getSelectionStart(), mainEditText.getSelectionEnd(), ':'+emoji.shortcode+':');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateToolbar(){
|
||||||
|
getToolbar().setNavigationIcon(R.drawable.ic_fluent_dismiss_24_regular);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onPublishClick(View v){
|
||||||
|
publish();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void publish(){
|
||||||
|
String text=mainEditText.getText().toString();
|
||||||
|
CreateStatus.Request req=new CreateStatus.Request();
|
||||||
|
req.status=text;
|
||||||
|
if(!attachments.isEmpty()){
|
||||||
|
req.mediaIds=attachments.stream().map(a->a.serverAttachment.id).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
String uuid=UUID.randomUUID().toString();
|
||||||
|
ProgressDialog progress=new ProgressDialog(getActivity());
|
||||||
|
progress.setMessage(getString(R.string.publishing));
|
||||||
|
progress.setCancelable(false);
|
||||||
|
progress.show();
|
||||||
|
new CreateStatus(req, uuid)
|
||||||
|
.setCallback(new Callback<>(){
|
||||||
|
@Override
|
||||||
|
public void onSuccess(Status result){
|
||||||
|
progress.dismiss();
|
||||||
|
Nav.finish(ComposeFragment.this);
|
||||||
|
E.post(new StatusCreatedEvent(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(ErrorResponse error){
|
||||||
|
progress.dismiss();
|
||||||
|
error.showToast(getActivity());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.exec(accountID);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasDraft(){
|
||||||
|
return mainEditText.length()>0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onBackPressed(){
|
||||||
|
if(emojiKeyboard.isVisible()){
|
||||||
|
emojiKeyboard.hide();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(hasDraft()){
|
||||||
|
confirmDiscardDraftAndFinish();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onToolbarNavigationClick(){
|
||||||
|
if(hasDraft()){
|
||||||
|
confirmDiscardDraftAndFinish();
|
||||||
|
}else{
|
||||||
|
super.onToolbarNavigationClick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void confirmDiscardDraftAndFinish(){
|
||||||
|
new M3AlertDialogBuilder(getActivity())
|
||||||
|
.setTitle(R.string.discard_draft)
|
||||||
|
.setPositiveButton(R.string.discard, (dialog, which)->Nav.finish(this))
|
||||||
|
.setNegativeButton(R.string.cancel, null)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void openFilePicker(){
|
||||||
|
Intent intent=new Intent(Intent.ACTION_GET_CONTENT);
|
||||||
|
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||||
|
intent.setType("*/*");
|
||||||
|
intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[]{"image/*", "video/*"});
|
||||||
|
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
|
||||||
|
startActivityForResult(intent, MEDIA_RESULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityResult(int requestCode, int resultCode, Intent data){
|
||||||
|
if(requestCode==MEDIA_RESULT && resultCode==Activity.RESULT_OK){
|
||||||
|
Uri single=data.getData();
|
||||||
|
if(single!=null){
|
||||||
|
addMediaAttachment(single);
|
||||||
|
}else{
|
||||||
|
ClipData clipData=data.getClipData();
|
||||||
|
for(int i=0;i<clipData.getItemCount();i++){
|
||||||
|
addMediaAttachment(clipData.getItemAt(i).getUri());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addMediaAttachment(Uri uri){
|
||||||
|
View thumb=getActivity().getLayoutInflater().inflate(R.layout.compose_media_thumb, attachmentsView, false);
|
||||||
|
ImageView img=thumb.findViewById(R.id.thumb);
|
||||||
|
ViewImageLoader.load(img, null, new UrlImageLoaderRequest(uri, V.dp(250), V.dp(250)));
|
||||||
|
attachmentsView.addView(thumb);
|
||||||
|
|
||||||
|
DraftMediaAttachment draft=new DraftMediaAttachment();
|
||||||
|
draft.uri=uri;
|
||||||
|
draft.view=thumb;
|
||||||
|
draft.progressBar=thumb.findViewById(R.id.progress);
|
||||||
|
Button btn=thumb.findViewById(R.id.remove_btn);
|
||||||
|
btn.setTag(draft);
|
||||||
|
btn.setOnClickListener(this::onRemoveMediaAttachmentClick);
|
||||||
|
|
||||||
|
if(uploadingAttachment==null){
|
||||||
|
uploadMediaAttachment(draft);
|
||||||
|
}else{
|
||||||
|
queuedAttachments.add(draft);
|
||||||
|
}
|
||||||
|
updatePublishButtonState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void uploadMediaAttachment(DraftMediaAttachment attachment){
|
||||||
|
if(uploadingAttachment!=null)
|
||||||
|
throw new IllegalStateException("there is already an attachment being uploaded");
|
||||||
|
uploadingAttachment=attachment;
|
||||||
|
attachment.uploadRequest=(UploadAttachment) new UploadAttachment(attachment.uri)
|
||||||
|
.setProgressListener(new ProgressListener(){
|
||||||
|
@Override
|
||||||
|
public void onProgress(long transferred, long total){
|
||||||
|
int progress=Math.round(transferred/(float)total*attachment.progressBar.getMax());
|
||||||
|
if(Build.VERSION.SDK_INT>=24)
|
||||||
|
attachment.progressBar.setProgress(progress, true);
|
||||||
|
else
|
||||||
|
attachment.progressBar.setProgress(progress);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setCallback(new Callback<>(){
|
||||||
|
@Override
|
||||||
|
public void onSuccess(Attachment result){
|
||||||
|
attachment.serverAttachment=result;
|
||||||
|
attachment.uploadRequest=null;
|
||||||
|
uploadingAttachment=null;
|
||||||
|
attachments.add(attachment);
|
||||||
|
attachment.progressBar.setVisibility(View.GONE);
|
||||||
|
if(!queuedAttachments.isEmpty())
|
||||||
|
uploadMediaAttachment(queuedAttachments.remove(0));
|
||||||
|
updatePublishButtonState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(ErrorResponse error){
|
||||||
|
attachment.uploadRequest=null;
|
||||||
|
uploadingAttachment=null;
|
||||||
|
failedAttachments.add(attachment);
|
||||||
|
error.showToast(getActivity());
|
||||||
|
// TODO show the error state in the attachment view
|
||||||
|
|
||||||
|
if(!queuedAttachments.isEmpty())
|
||||||
|
uploadMediaAttachment(queuedAttachments.remove(0));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.exec(accountID);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onRemoveMediaAttachmentClick(View v){
|
||||||
|
DraftMediaAttachment att=(DraftMediaAttachment) v.getTag();
|
||||||
|
if(att==uploadingAttachment){
|
||||||
|
att.uploadRequest.cancel();
|
||||||
|
if(!queuedAttachments.isEmpty())
|
||||||
|
uploadMediaAttachment(queuedAttachments.remove(0));
|
||||||
|
}else{
|
||||||
|
attachments.remove(att);
|
||||||
|
queuedAttachments.remove(att);
|
||||||
|
failedAttachments.remove(att);
|
||||||
|
}
|
||||||
|
attachmentsView.removeView(att.view);
|
||||||
|
updatePublishButtonState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class DraftMediaAttachment{
|
||||||
|
public Attachment serverAttachment;
|
||||||
|
public Uri uri;
|
||||||
|
public UploadAttachment uploadRequest;
|
||||||
|
|
||||||
|
public View view;
|
||||||
|
public ProgressBar progressBar;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
package org.joinmastodon.android.ui;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.Button;
|
||||||
|
|
||||||
|
import me.grishka.appkit.utils.V;
|
||||||
|
|
||||||
|
public class M3AlertDialogBuilder extends AlertDialog.Builder{
|
||||||
|
public M3AlertDialogBuilder(Context context){
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public M3AlertDialogBuilder(Context context, int themeResId){
|
||||||
|
super(context, themeResId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AlertDialog create(){
|
||||||
|
AlertDialog alert=super.create();
|
||||||
|
alert.create();
|
||||||
|
Button btn=alert.getButton(AlertDialog.BUTTON_POSITIVE);
|
||||||
|
if(btn!=null){
|
||||||
|
View buttonBar=(View) btn.getParent();
|
||||||
|
buttonBar.setPadding(V.dp(16), V.dp(24), V.dp(16), V.dp(24));
|
||||||
|
((View)buttonBar.getParent()).setPadding(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
return alert;
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,8 @@ import android.content.Context;
|
||||||
import android.content.res.ColorStateList;
|
import android.content.res.ColorStateList;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
@ -15,6 +17,8 @@ import androidx.annotation.ColorRes;
|
||||||
import androidx.browser.customtabs.CustomTabsIntent;
|
import androidx.browser.customtabs.CustomTabsIntent;
|
||||||
|
|
||||||
public class UiUtils{
|
public class UiUtils{
|
||||||
|
private static Handler mainHandler=new Handler(Looper.getMainLooper());
|
||||||
|
|
||||||
private UiUtils(){}
|
private UiUtils(){}
|
||||||
|
|
||||||
public static void launchWebBrowser(Context context, String url){
|
public static void launchWebBrowser(Context context, String url){
|
||||||
|
@ -56,4 +60,8 @@ public class UiUtils{
|
||||||
}
|
}
|
||||||
textView.setCompoundDrawablesRelative(drawables[0], drawables[1], drawables[2], drawables[3]);
|
textView.setCompoundDrawablesRelative(drawables[0], drawables[1], drawables[2], drawables[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void runOnUiThread(Runnable runnable){
|
||||||
|
mainHandler.post(runnable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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:state_enabled="true"/>
|
||||||
|
<item android:color="@color/gray_800_alpha50"/>
|
||||||
|
</selector>
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<inset xmlns:android="http://schemas.android.com/apk/res/android" android:inset="16dp">
|
||||||
|
<shape>
|
||||||
|
<solid android:color="?android:attr/colorBackground"/>
|
||||||
|
<corners android:radius="16dp"/>
|
||||||
|
</shape>
|
||||||
|
</inset>
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="?android:attr/colorControlHighlight">
|
||||||
|
<item android:id="@android:id/mask">
|
||||||
|
<shape>
|
||||||
|
<solid android:color="#000"/>
|
||||||
|
<corners android:radius="100dp"/>
|
||||||
|
<padding android:top="10dp" android:bottom="10dp" android:left="12dp" android:right="12dp"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</ripple>
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item>
|
||||||
|
<ripple android:color="@color/highlight_over_dark">
|
||||||
|
<item>
|
||||||
|
<shape>
|
||||||
|
<solid android:color="@color/button_bg"/>
|
||||||
|
<corners android:radius="10dp"/>
|
||||||
|
<padding android:left="16dp" android:right="16dp" android:top="8dp" android:bottom="8dp"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</ripple>
|
||||||
|
</item>
|
||||||
|
</selector>
|
|
@ -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="M22 11.998c0-5.523-4.477-10-10-10s-10 4.477-10 10c0 1.643 0.397 3.23 1.145 4.65l-1.116 4.289c-0.037 0.14-0.037 0.288 0 0.428 0.118 0.454 0.582 0.727 1.036 0.608l4.29-1.117c1.42 0.746 3.005 1.142 4.645 1.142 5.523 0 10-4.477 10-10zM12 6.5c0.414 0 0.75 0.335 0.75 0.75v6.25c0 0.414-0.336 0.75-0.75 0.75s-0.75-0.336-0.75-0.75V7.25c0-0.415 0.336-0.75 0.75-0.75zm1 9.997c0 0.553-0.448 1-1 1s-1-0.447-1-1c0-0.552 0.448-1 1-1s1 0.448 1 1z" android:fillColor="@color/fluent_default_icon_tint"/>
|
||||||
|
</vector>
|
|
@ -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 6.5c0.414 0 0.75 0.336 0.75 0.75v6.25c0 0.414-0.336 0.75-0.75 0.75s-0.75-0.336-0.75-0.75V7.25c0-0.414 0.336-0.75 0.75-0.75zm0 10.998c0.552 0 1-0.448 1-1 0-0.553-0.448-1-1-1s-1 0.447-1 1c0 0.552 0.448 1 1 1zM12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10c-1.618 0-3.182-0.385-4.587-1.112l-3.826 1.067c-0.665 0.186-1.354-0.202-1.54-0.867-0.062-0.22-0.062-0.453 0-0.673l1.068-3.823C2.386 15.186 2 13.62 2 12 2 6.477 6.477 2 12 2zm0 1.5c-4.694 0-8.5 3.806-8.5 8.5 0 1.47 0.373 2.883 1.073 4.137l0.15 0.27-1.112 3.984 3.986-1.112 0.27 0.15C9.12 20.13 10.532 20.5 12 20.5c4.694 0 8.5-3.806 8.5-8.5S16.694 3.5 12 3.5z" android:fillColor="@color/fluent_default_icon_tint"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--~ Copyright (c) 2022. ~ Microsoft Corporation. All rights reserved.-->
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:drawable="@drawable/ic_fluent_chat_warning_24_filled" android:state_activated="true"/>
|
||||||
|
<item android:drawable="@drawable/ic_fluent_chat_warning_24_filled" android:state_checked="true"/>
|
||||||
|
<item android:drawable="@drawable/ic_fluent_chat_warning_24_filled" android:state_selected="true"/>
|
||||||
|
<item android:drawable="@drawable/ic_fluent_chat_warning_24_regular"/>
|
||||||
|
</selector>
|
|
@ -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="M4.397 4.554L4.47 4.47c0.266-0.267 0.683-0.29 0.976-0.073L5.53 4.47 12 10.939l6.47-6.47c0.293-0.292 0.767-0.292 1.06 0 0.293 0.294 0.293 0.768 0 1.061L13.061 12l6.47 6.47c0.266 0.266 0.29 0.683 0.072 0.976L19.53 19.53c-0.266 0.267-0.683 0.29-0.976 0.073L18.47 19.53 12 13.061l-6.47 6.47c-0.293 0.292-0.767 0.292-1.06 0-0.293-0.294-0.293-0.768 0-1.061L10.939 12l-6.47-6.47C4.204 5.264 4.18 4.847 4.398 4.554L4.47 4.47 4.397 4.554z" android:fillColor="@color/fluent_default_icon_tint"/>
|
||||||
|
</vector>
|
|
@ -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="M17.75 3C19.545 3 21 4.455 21 6.25v11.5c0 1.795-1.455 3.25-3.25 3.25H6.25C4.455 21 3 19.545 3 17.75V6.25C3 4.455 4.455 3 6.25 3h11.5zm0.58 16.401l-5.805-5.686c-0.265-0.26-0.675-0.283-0.966-0.071l-0.084 0.07-5.807 5.687C5.85 19.465 6.046 19.5 6.25 19.5h11.5c0.203 0 0.399-0.035 0.58-0.099l-5.805-5.686L18.33 19.4zM17.75 4.5H6.25C5.284 4.5 4.5 5.284 4.5 6.25v11.5c0 0.208 0.036 0.408 0.103 0.594l5.823-5.701c0.833-0.816 2.142-0.854 3.02-0.116l0.128 0.116 5.822 5.702c0.067-0.186 0.104-0.386 0.104-0.595V6.25c0-0.966-0.784-1.75-1.75-1.75zm-2.498 2c1.244 0 2.252 1.008 2.252 2.252 0 1.244-1.008 2.252-2.252 2.252-1.244 0-2.252-1.008-2.252-2.252C13 7.508 14.008 6.5 15.252 6.5zm0 1.5C14.837 8 14.5 8.337 14.5 8.752s0.337 0.752 0.752 0.752 0.752-0.336 0.752-0.752C16.004 8.337 15.667 8 15.252 8z" android:fillColor="@color/fluent_default_icon_tint"/>
|
||||||
|
</vector>
|
|
@ -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="M14.75 15c0.966 0 1.75 0.784 1.75 1.75l-0.001 0.962c0.117 2.19-1.511 3.297-4.432 3.297-2.91 0-4.567-1.09-4.567-3.259v-1C7.5 15.784 8.284 15 9.25 15h5.5zm0 1.5h-5.5C9.112 16.5 9 16.612 9 16.75v1c0 1.176 0.887 1.759 3.067 1.759 2.168 0 2.995-0.564 2.933-1.757V16.75c0-0.138-0.112-0.25-0.25-0.25zm-11-6.5h4.376C8.044 10.32 8 10.655 8 11c0 0.17 0.01 0.336 0.03 0.5H3.75c-0.138 0-0.25 0.112-0.25 0.25v1c0 1.176 0.887 1.759 3.067 1.759 0.462 0 0.863-0.026 1.207-0.077-0.565 0.358-0.989 0.917-1.173 1.576L6.567 16.01C3.657 16.009 2 14.919 2 12.75v-1C2 10.784 2.784 10 3.75 10zm16.5 0c0.966 0 1.75 0.784 1.75 1.75l-0.001 0.962c0.117 2.19-1.511 3.297-4.432 3.297l-0.169-0.002c-0.189-0.677-0.631-1.248-1.218-1.606 0.387 0.072 0.847 0.108 1.387 0.108 2.168 0 2.995-0.564 2.933-1.757V11.75c0-0.138-0.112-0.25-0.25-0.25h-4.28C15.99 11.335 16 11.17 16 11c0-0.345-0.044-0.68-0.126-1h4.376zM12 8c1.657 0 3 1.343 3 3s-1.343 3-3 3-3-1.343-3-3 1.343-3 3-3zm0 1.5c-0.828 0-1.5 0.672-1.5 1.5s0.672 1.5 1.5 1.5 1.5-0.672 1.5-1.5-0.672-1.5-1.5-1.5zM6.5 3c1.657 0 3 1.343 3 3s-1.343 3-3 3-3-1.343-3-3 1.343-3 3-3zm11 0c1.657 0 3 1.343 3 3s-1.343 3-3 3-3-1.343-3-3 1.343-3 3-3zm-11 1.5C5.672 4.5 5 5.172 5 6s0.672 1.5 1.5 1.5S8 6.828 8 6 7.328 4.5 6.5 4.5zm11 0C16.672 4.5 16 5.172 16 6s0.672 1.5 1.5 1.5S19 6.828 19 6s-0.672-1.5-1.5-1.5z" android:fillColor="@color/fluent_default_icon_tint"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,3 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="25dp" android:height="24dp" android:viewportWidth="25" android:viewportHeight="24">
|
||||||
|
<path android:pathData="M12.168 2c1.52 0 2.752 1.232 2.752 2.752V19.25c0 1.52-1.232 2.752-2.752 2.752-1.52 0-2.752-1.232-2.752-2.752V4.752C9.416 3.232 10.648 2 12.168 2zm7 5c1.52 0 2.752 1.232 2.752 2.752v9.498c0 1.52-1.232 2.752-2.752 2.752-1.52 0-2.752-1.232-2.752-2.752V9.752c0-1.52 1.232-2.752 2.752-2.752zm-14 5c1.52 0 2.752 1.232 2.752 2.752v4.498c0 1.52-1.232 2.752-2.752 2.752-1.52 0-2.752-1.232-2.752-2.752v-4.498c0-1.52 1.232-2.752 2.752-2.752z" android:fillColor="@color/fluent_default_icon_tint"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,3 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="25dp" android:height="24dp" android:viewportWidth="25" android:viewportHeight="24">
|
||||||
|
<path android:pathData="M12.168 2c1.52 0 2.752 1.232 2.752 2.752V19.25c0 1.52-1.232 2.752-2.752 2.752-1.52 0-2.752-1.232-2.752-2.752V4.752C9.416 3.232 10.648 2 12.168 2zm7 5c1.52 0 2.752 1.232 2.752 2.752v9.498c0 1.52-1.232 2.752-2.752 2.752-1.52 0-2.752-1.232-2.752-2.752V9.752c0-1.52 1.232-2.752 2.752-2.752zm-14 5c1.52 0 2.752 1.232 2.752 2.752v4.498c0 1.52-1.232 2.752-2.752 2.752-1.52 0-2.752-1.232-2.752-2.752v-4.498c0-1.52 1.232-2.752 2.752-2.752zm7-8.5c-0.691 0-1.252 0.56-1.252 1.252V19.25c0 0.692 0.56 1.252 1.252 1.252 0.691 0 1.252-0.56 1.252-1.252V4.752c0-0.691-0.56-1.252-1.252-1.252zm7 5c-0.691 0-1.252 0.56-1.252 1.252v9.498c0 0.692 0.56 1.252 1.252 1.252 0.691 0 1.252-0.56 1.252-1.252V9.752c0-0.692-0.56-1.252-1.252-1.252zm-14 5c-0.692 0-1.252 0.56-1.252 1.252v4.498c0 0.692 0.56 1.252 1.252 1.252 0.691 0 1.252-0.56 1.252-1.252v-4.498c0-0.692-0.56-1.252-1.252-1.252z" android:fillColor="@color/fluent_default_icon_tint"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--~ Copyright (c) 2022. ~ Microsoft Corporation. All rights reserved.-->
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:drawable="@drawable/ic_fluent_poll_24_filled" android:state_activated="true"/>
|
||||||
|
<item android:drawable="@drawable/ic_fluent_poll_24_filled" android:state_checked="true"/>
|
||||||
|
<item android:drawable="@drawable/ic_fluent_poll_24_filled" android:state_selected="true"/>
|
||||||
|
<item android:drawable="@drawable/ic_fluent_poll_24_regular"/>
|
||||||
|
</selector>
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="250dp"
|
||||||
|
android:layout_height="150dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/thumb"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:scaleType="centerCrop"/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/remove_btn"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="top|right"
|
||||||
|
android:text="X"/>
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progress"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
style="?android:progressBarStyleHorizontal"/>
|
||||||
|
|
||||||
|
</FrameLayout>
|
|
@ -5,62 +5,76 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<RelativeLayout
|
<ScrollView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="0dp"
|
||||||
android:paddingTop="16dp"
|
|
||||||
android:paddingRight="16dp"
|
|
||||||
android:paddingLeft="16dp">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/avatar"
|
|
||||||
android:layout_width="46dp"
|
|
||||||
android:layout_height="46dp"
|
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:layout_alignParentTop="true"
|
|
||||||
android:layout_marginEnd="12dp" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/name"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="24dp"
|
|
||||||
android:layout_toEndOf="@id/avatar"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:textAppearance="@style/m3_title_medium"
|
|
||||||
tools:text="Eugen" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/username"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="20dp"
|
|
||||||
android:layout_below="@id/name"
|
|
||||||
android:layout_toEndOf="@id/avatar"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:textAppearance="@style/m3_title_small"
|
|
||||||
tools:text="\@Gargron" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/toot_text"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0px"
|
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:layout_marginTop="10dp"
|
android:fillViewport="true">
|
||||||
android:paddingLeft="16dp"
|
|
||||||
android:paddingRight="16dp"
|
|
||||||
android:paddingBottom="16dp"
|
|
||||||
android:textAppearance="@style/m3_body_large"
|
|
||||||
android:gravity="top"
|
|
||||||
android:background="@null"
|
|
||||||
android:inputType="textMultiLine|textCapSentences"/>
|
|
||||||
|
|
||||||
<View
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="1dp"
|
android:layout_height="wrap_content"
|
||||||
android:background="#20000000"/>
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingTop="16dp"
|
||||||
|
android:paddingRight="16dp"
|
||||||
|
android:paddingLeft="16dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/avatar"
|
||||||
|
android:layout_width="46dp"
|
||||||
|
android:layout_height="46dp"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_marginEnd="12dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/name"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_toEndOf="@id/avatar"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textAppearance="@style/m3_title_medium"
|
||||||
|
tools:text="Eugen" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/username"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:layout_below="@id/name"
|
||||||
|
android:layout_toEndOf="@id/avatar"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textAppearance="@style/m3_title_small"
|
||||||
|
tools:text="\@Gargron" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/toot_text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:paddingLeft="16dp"
|
||||||
|
android:paddingRight="16dp"
|
||||||
|
android:paddingBottom="16dp"
|
||||||
|
android:textAppearance="@style/m3_body_large"
|
||||||
|
android:gravity="top"
|
||||||
|
android:background="@null"
|
||||||
|
android:inputType="textMultiLine|textCapSentences"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/attachments"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -68,18 +82,58 @@
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:background="@color/gray_25"
|
android:background="@color/gray_25"
|
||||||
|
android:elevation="2dp"
|
||||||
|
android:outlineProvider="bounds"
|
||||||
android:paddingLeft="16dp"
|
android:paddingLeft="16dp"
|
||||||
android:paddingRight="16dp">
|
android:paddingRight="16dp"
|
||||||
|
android:layoutDirection="locale">
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/btn_media"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginEnd="24dp"
|
||||||
|
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||||
|
android:padding="0px"
|
||||||
|
android:src="@drawable/ic_fluent_image_24_regular"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/btn_poll"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginEnd="24dp"
|
||||||
|
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||||
|
android:padding="0px"
|
||||||
|
android:src="@drawable/ic_fluent_poll_24_selector"/>
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/btn_emoji"
|
android:id="@+id/btn_emoji"
|
||||||
android:layout_width="24dp"
|
android:layout_width="24dp"
|
||||||
android:layout_height="24dp"
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginEnd="24dp"
|
||||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||||
android:padding="0px"
|
android:padding="0px"
|
||||||
android:src="@drawable/ic_fluent_emoji_24_selector"/>
|
android:src="@drawable/ic_fluent_emoji_24_selector"/>
|
||||||
|
|
||||||
<View
|
<ImageButton
|
||||||
|
android:id="@+id/btn_spoiler"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginEnd="24dp"
|
||||||
|
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||||
|
android:padding="0px"
|
||||||
|
android:src="@drawable/ic_fluent_chat_warning_24_selector"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/btn_visibility"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginEnd="24dp"
|
||||||
|
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||||
|
android:padding="0px"
|
||||||
|
android:src="@drawable/ic_fluent_people_community_24_regular"/>
|
||||||
|
|
||||||
|
<Space
|
||||||
android:layout_width="0px"
|
android:layout_width="0px"
|
||||||
android:layout_height="1px"
|
android:layout_height="1px"
|
||||||
android:layout_weight="1"/>
|
android:layout_weight="1"/>
|
||||||
|
|
|
@ -12,10 +12,13 @@
|
||||||
|
|
||||||
<color name="gray_25">#FCFCFD</color>
|
<color name="gray_25">#FCFCFD</color>
|
||||||
<color name="gray_50t">#CCF9FAFB</color>
|
<color name="gray_50t">#CCF9FAFB</color>
|
||||||
|
<color name="gray_50">#F9FAFB</color>
|
||||||
<color name="gray_100">#F2F4F7</color>
|
<color name="gray_100">#F2F4F7</color>
|
||||||
<color name="gray_800">#282C37</color>
|
<color name="gray_800">#282C37</color>
|
||||||
<color name="gray_500">#667085</color>
|
<color name="gray_500">#667085</color>
|
||||||
|
|
||||||
|
<color name="gray_800_alpha50">#80282C37</color>
|
||||||
|
|
||||||
<color name="text_primary">@color/gray_800</color>
|
<color name="text_primary">@color/gray_800</color>
|
||||||
<color name="text_secondary">@color/gray_500</color>
|
<color name="text_secondary">@color/gray_500</color>
|
||||||
<color name="secondary">#E9EDF2</color>
|
<color name="secondary">#E9EDF2</color>
|
||||||
|
@ -23,6 +26,7 @@
|
||||||
<color name="text_secondary_alpha50">#80667085</color>
|
<color name="text_secondary_alpha50">#80667085</color>
|
||||||
<color name="actionbar_bg">#FAFBFC</color>
|
<color name="actionbar_bg">#FAFBFC</color>
|
||||||
<color name="navigation_bar_bg">#000</color>
|
<color name="navigation_bar_bg">#000</color>
|
||||||
|
<color name="highlight_over_dark">#80FFFFFF</color>
|
||||||
|
|
||||||
<color name="favorite_selected">#FF9F0A</color>
|
<color name="favorite_selected">#FF9F0A</color>
|
||||||
<color name="boost_selected">#79BD9A</color>
|
<color name="boost_selected">#79BD9A</color>
|
||||||
|
|
|
@ -28,4 +28,9 @@
|
||||||
|
|
||||||
<string name="share_toot_title">Share toot</string>
|
<string name="share_toot_title">Share toot</string>
|
||||||
<string name="settings">Settings</string>
|
<string name="settings">Settings</string>
|
||||||
|
<string name="publish">Publish</string>
|
||||||
|
<string name="discard_draft">Discard draft?</string>
|
||||||
|
<string name="discard">Discard</string>
|
||||||
|
<string name="cancel">Cancel</string>
|
||||||
|
<string name="publishing">Your toot is being tooted</string>
|
||||||
</resources>
|
</resources>
|
|
@ -1,17 +1,20 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
<style name="Theme.Mastodon" parent="Theme.AppKit.Light">
|
<style name="Theme.Mastodon" parent="Theme.AppKit.Light">
|
||||||
<!-- needed to disable scrim on API 29+ -->
|
<!-- needed to disable scrim on API 29+ -->
|
||||||
<item name="android:enforceNavigationBarContrast">false</item>
|
<item name="android:enforceNavigationBarContrast" tools:ignore="NewApi">false</item>
|
||||||
<item name="android:enforceStatusBarContrast">false</item>
|
<item name="android:enforceStatusBarContrast" tools:ignore="NewApi">false</item>
|
||||||
<item name="android:windowLightStatusBar">true</item>
|
<item name="android:windowLightStatusBar">true</item>
|
||||||
<item name="android:windowLightNavigationBar">true</item>
|
<item name="android:windowLightNavigationBar" tools:ignore="NewApi">true</item>
|
||||||
<item name="android:windowBackground">@color/white</item>
|
<item name="android:windowBackground">@color/white</item>
|
||||||
<item name="android:statusBarColor">@color/actionbar_bg</item>
|
<item name="android:statusBarColor">@color/actionbar_bg</item>
|
||||||
<item name="android:navigationBarColor">@color/navigation_bar_bg</item>
|
<item name="android:navigationBarColor">@color/navigation_bar_bg</item>
|
||||||
<item name="android:colorAccent">@color/gray_800</item>
|
<item name="android:colorAccent">@color/gray_800</item>
|
||||||
<item name="android:colorPrimary">@color/gray_800</item>
|
<item name="android:colorPrimary">@color/gray_800</item>
|
||||||
|
<item name="android:colorBackground">@color/gray_100</item>
|
||||||
<item name="android:actionBarTheme">@style/Theme.Mastodon.Toolbar</item>
|
<item name="android:actionBarTheme">@style/Theme.Mastodon.Toolbar</item>
|
||||||
|
<item name="android:buttonStyle">@style/Widget.Mastodon.Button</item>
|
||||||
|
<item name="android:alertDialogTheme">@style/Theme.Mastodon.Dialog.Alert</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="Theme.Mastodon.Toolbar" parent="android:ThemeOverlay.Material.ActionBar">
|
<style name="Theme.Mastodon.Toolbar" parent="android:ThemeOverlay.Material.ActionBar">
|
||||||
|
@ -20,6 +23,53 @@
|
||||||
<item name="android:textColorSecondary">@color/gray_800</item>
|
<item name="android:textColorSecondary">@color/gray_800</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="Widget.Mastodon.Button" parent="android:Widget.Material.Button">
|
||||||
|
<item name="android:textAllCaps">false</item>
|
||||||
|
<item name="android:background">@drawable/bg_button</item>
|
||||||
|
<item name="android:textAppearance">@style/m3_label_large</item>
|
||||||
|
<item name="android:textColor">@color/gray_50</item>
|
||||||
|
<item name="android:minHeight">36dp</item>
|
||||||
|
<item name="android:minWidth">0px</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="Theme.Mastodon.Dialog.Alert" parent="android:Theme.Material.Light.Dialog.Alert">
|
||||||
|
<item name="android:windowTitleStyle">@style/alert_title</item>
|
||||||
|
<item name="android:dialogPreferredPadding">24dp</item>
|
||||||
|
<item name="android:windowBackground">@drawable/bg_alert</item>
|
||||||
|
<item name="android:colorBackground">@color/gray_100</item>
|
||||||
|
<item name="android:buttonBarStyle">@style/Widget.Mastodon.ButtonBar</item>
|
||||||
|
<item name="android:buttonBarButtonStyle">@style/Widget.Mastodon.ButtonBarButton</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="Widget.Mastodon.ButtonBar" parent="android:Widget.Material.Light.ButtonBar.AlertDialog">
|
||||||
|
<!-- <item name="android:layout_marginEnd">4dp</item>-->
|
||||||
|
<!-- <item name="android:layout_marginStart">12dp</item>-->
|
||||||
|
<!-- <item name="android:layout_marginTop">20dp</item>-->
|
||||||
|
<!-- <item name="android:layout_marginBottom">20dp</item>-->
|
||||||
|
|
||||||
|
<!-- <item name="android:paddingEnd">4dp</item>-->
|
||||||
|
<!-- <item name="android:paddingStart">12dp</item>-->
|
||||||
|
<!-- <item name="android:paddingTop">20dp</item>-->
|
||||||
|
<!-- <item name="android:paddingBottom">20dp</item>-->
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="Widget.Mastodon.ButtonBarButton" parent="android:Widget.Material.Button.Borderless">
|
||||||
|
<item name="android:textAllCaps">false</item>
|
||||||
|
<item name="android:layout_marginEnd">8dp</item>
|
||||||
|
<item name="android:minHeight">40dp</item>
|
||||||
|
<item name="android:minWidth">0px</item>
|
||||||
|
<item name="android:background">@drawable/bg_alert_button</item>
|
||||||
|
<item name="android:textAppearance">@style/m3_label_large</item>
|
||||||
|
<item name="android:textColor">@color/text_primary</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="alert_title">
|
||||||
|
<item name="android:textColor">@color/text_primary</item>
|
||||||
|
<item name="android:textSize">24dp</item>
|
||||||
|
<item name="android:minHeight">38dp</item>
|
||||||
|
<item name="android:gravity">bottom</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<style name="m3_body_large">
|
<style name="m3_body_large">
|
||||||
<item name="android:textSize">16dp</item>
|
<item name="android:textSize">16dp</item>
|
||||||
<item name="android:textColor">@color/text_primary</item>
|
<item name="android:textColor">@color/text_primary</item>
|
||||||
|
|
Loading…
Reference in New Issue