Post edit history + extended footer redesign
This commit is contained in:
parent
265b2ad32c
commit
8fb2b454dd
@ -0,0 +1,33 @@
|
|||||||
|
package org.joinmastodon.android.api.requests.statuses;
|
||||||
|
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.api.MastodonAPIRequest;
|
||||||
|
import org.joinmastodon.android.model.Status;
|
||||||
|
import org.joinmastodon.android.model.StatusPrivacy;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import okhttp3.Response;
|
||||||
|
|
||||||
|
public class GetStatusEditHistory extends MastodonAPIRequest<List<Status>>{
|
||||||
|
public GetStatusEditHistory(String id){
|
||||||
|
super(HttpMethod.GET, "/statuses/"+id+"/history", new TypeToken<>(){});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validateAndPostprocessResponse(List<Status> respObj, Response httpResponse) throws IOException{
|
||||||
|
int i=0;
|
||||||
|
for(Status s:respObj){
|
||||||
|
s.uri="";
|
||||||
|
s.id="fakeID"+i;
|
||||||
|
s.visibility=StatusPrivacy.PUBLIC;
|
||||||
|
s.mentions=Collections.emptyList();
|
||||||
|
s.tags=Collections.emptyList();
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
super.validateAndPostprocessResponse(respObj, httpResponse);
|
||||||
|
}
|
||||||
|
}
|
@ -579,6 +579,10 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ArrayList<StatusDisplayItem> getDisplayItems(){
|
||||||
|
return displayItems;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onApplyWindowInsets(WindowInsets insets){
|
public void onApplyWindowInsets(WindowInsets insets){
|
||||||
if(Build.VERSION.SDK_INT>=29 && insets.getTappableElementInsets().bottom==0 && wantsOverlaySystemNavigation()){
|
if(Build.VERSION.SDK_INT>=29 && insets.getTappableElementInsets().bottom==0 && wantsOverlaySystemNavigation()){
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
package org.joinmastodon.android.fragments;
|
package org.joinmastodon.android.fragments;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.graphics.Canvas;
|
|
||||||
import android.graphics.Paint;
|
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.graphics.RectF;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
@ -16,15 +12,12 @@ import org.joinmastodon.android.api.session.AccountSessionManager;
|
|||||||
import org.joinmastodon.android.events.PollUpdatedEvent;
|
import org.joinmastodon.android.events.PollUpdatedEvent;
|
||||||
import org.joinmastodon.android.model.Notification;
|
import org.joinmastodon.android.model.Notification;
|
||||||
import org.joinmastodon.android.model.PaginatedResponse;
|
import org.joinmastodon.android.model.PaginatedResponse;
|
||||||
import org.joinmastodon.android.model.Poll;
|
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
import org.joinmastodon.android.ui.PhotoLayoutHelper;
|
|
||||||
import org.joinmastodon.android.ui.displayitems.AccountCardStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.AccountCardStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.ImageStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.ImageStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.LinkCardStatusDisplayItem;
|
|
||||||
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.InsetStatusItemDecoration;
|
||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -33,7 +26,6 @@ import java.util.List;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import me.grishka.appkit.Nav;
|
import me.grishka.appkit.Nav;
|
||||||
import me.grishka.appkit.api.SimpleCallback;
|
import me.grishka.appkit.api.SimpleCallback;
|
||||||
@ -160,91 +152,7 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
|
|||||||
@Override
|
@Override
|
||||||
public void onViewCreated(View view, Bundle savedInstanceState){
|
public void onViewCreated(View view, Bundle savedInstanceState){
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
list.addItemDecoration(new RecyclerView.ItemDecoration(){
|
list.addItemDecoration(new InsetStatusItemDecoration(this));
|
||||||
private Paint paint=new Paint(Paint.ANTI_ALIAS_FLAG);
|
|
||||||
private int bgColor=UiUtils.getThemeColor(getActivity(), android.R.attr.colorBackground);
|
|
||||||
private int borderColor=UiUtils.getThemeColor(getActivity(), R.attr.colorPollVoted);
|
|
||||||
private RectF rect=new RectF();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state){
|
|
||||||
int pos=0;
|
|
||||||
for(int i=0;i<parent.getChildCount();i++){
|
|
||||||
View child=parent.getChildAt(i);
|
|
||||||
RecyclerView.ViewHolder holder=parent.getChildViewHolder(child);
|
|
||||||
pos=holder.getAbsoluteAdapterPosition();
|
|
||||||
boolean inset=(holder instanceof StatusDisplayItem.Holder<?> sdi) && sdi.getItem().inset;
|
|
||||||
if(inset){
|
|
||||||
if(rect.isEmpty()){
|
|
||||||
rect.set(child.getX(), i==0 && pos>0 && displayItems.get(pos-1).inset ? V.dp(-10) : child.getY(), child.getX()+child.getWidth(), child.getY()+child.getHeight());
|
|
||||||
}else{
|
|
||||||
rect.bottom=Math.max(rect.bottom, child.getY()+child.getHeight());
|
|
||||||
}
|
|
||||||
}else if(!rect.isEmpty()){
|
|
||||||
drawInsetBackground(c);
|
|
||||||
rect.setEmpty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!rect.isEmpty()){
|
|
||||||
if(pos<displayItems.size()-1 && displayItems.get(pos+1).inset){
|
|
||||||
rect.bottom=parent.getHeight()+V.dp(10);
|
|
||||||
}
|
|
||||||
drawInsetBackground(c);
|
|
||||||
rect.setEmpty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void drawInsetBackground(Canvas c){
|
|
||||||
paint.setStyle(Paint.Style.FILL);
|
|
||||||
paint.setColor(bgColor);
|
|
||||||
rect.left=V.dp(12);
|
|
||||||
rect.right=list.getWidth()-V.dp(12);
|
|
||||||
rect.inset(V.dp(4), V.dp(4));
|
|
||||||
c.drawRoundRect(rect, V.dp(4), V.dp(4), paint);
|
|
||||||
paint.setStyle(Paint.Style.STROKE);
|
|
||||||
paint.setStrokeWidth(V.dp(1));
|
|
||||||
paint.setColor(borderColor);
|
|
||||||
rect.inset(paint.getStrokeWidth()/2f, paint.getStrokeWidth()/2f);
|
|
||||||
c.drawRoundRect(rect, V.dp(4), V.dp(4), paint);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state){
|
|
||||||
RecyclerView.ViewHolder holder=parent.getChildViewHolder(view);
|
|
||||||
if(holder instanceof StatusDisplayItem.Holder<?> sdi){
|
|
||||||
boolean inset=sdi.getItem().inset;
|
|
||||||
int pos=holder.getAbsoluteAdapterPosition();
|
|
||||||
if(inset){
|
|
||||||
boolean topSiblingInset=pos>0 && displayItems.get(pos-1).inset;
|
|
||||||
boolean bottomSiblingInset=pos<displayItems.size()-1 && displayItems.get(pos+1).inset;
|
|
||||||
int pad;
|
|
||||||
if(holder instanceof ImageStatusDisplayItem.Holder || holder instanceof LinkCardStatusDisplayItem.Holder)
|
|
||||||
pad=V.dp(16);
|
|
||||||
else
|
|
||||||
pad=V.dp(12);
|
|
||||||
boolean insetLeft=true, insetRight=true;
|
|
||||||
if(holder instanceof ImageStatusDisplayItem.Holder<?> img){
|
|
||||||
PhotoLayoutHelper.TiledLayoutResult layout=img.getItem().tiledLayout;
|
|
||||||
PhotoLayoutHelper.TiledLayoutResult.Tile tile=img.getItem().thisTile;
|
|
||||||
// only inset those items that are on the edges of the layout
|
|
||||||
insetLeft=tile.startCol==0;
|
|
||||||
insetRight=tile.startCol+tile.colSpan==layout.columnSizes.length;
|
|
||||||
// inset all items in the bottom row
|
|
||||||
if(tile.startRow+tile.rowSpan==layout.rowSizes.length)
|
|
||||||
bottomSiblingInset=false;
|
|
||||||
}
|
|
||||||
if(insetLeft)
|
|
||||||
outRect.left=pad;
|
|
||||||
if(insetRight)
|
|
||||||
outRect.right=pad;
|
|
||||||
if(!topSiblingInset)
|
|
||||||
outRect.top=pad;
|
|
||||||
if(!bottomSiblingInset)
|
|
||||||
outRect.bottom=pad;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Notification getNotificationByID(String id){
|
private Notification getNotificationByID(String id){
|
||||||
@ -268,4 +176,5 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,157 @@
|
|||||||
|
package org.joinmastodon.android.fragments;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.R;
|
||||||
|
import org.joinmastodon.android.api.requests.statuses.GetStatusEditHistory;
|
||||||
|
import org.joinmastodon.android.model.Status;
|
||||||
|
import org.joinmastodon.android.ui.displayitems.ReblogOrReplyLineStatusDisplayItem;
|
||||||
|
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
||||||
|
import org.joinmastodon.android.ui.utils.InsetStatusItemDecoration;
|
||||||
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
|
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import me.grishka.appkit.api.SimpleCallback;
|
||||||
|
|
||||||
|
public class StatusEditHistoryFragment extends StatusListFragment{
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState){
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
id=getArguments().getString("id");
|
||||||
|
loadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Activity activity){
|
||||||
|
super.onAttach(activity);
|
||||||
|
setTitle(R.string.edit_history);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doLoadData(int offset, int count){
|
||||||
|
new GetStatusEditHistory(id)
|
||||||
|
.setCallback(new SimpleCallback<>(this){
|
||||||
|
@Override
|
||||||
|
public void onSuccess(List<Status> result){
|
||||||
|
Collections.sort(result, Comparator.comparing((Status s)->s.createdAt).reversed());
|
||||||
|
onDataLoaded(result, false);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.exec(accountID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<StatusDisplayItem> buildDisplayItems(Status s){
|
||||||
|
List<StatusDisplayItem> items=StatusDisplayItem.buildItems(this, s, accountID, s, knownAccounts, true, false);
|
||||||
|
int idx=data.indexOf(s);
|
||||||
|
if(idx>=0){
|
||||||
|
String date=UiUtils.DATE_TIME_FORMATTER.format(s.createdAt.atZone(ZoneId.systemDefault()));
|
||||||
|
String action="";
|
||||||
|
if(idx==data.size()-1){
|
||||||
|
action=getString(R.string.edit_original_post);
|
||||||
|
}else{
|
||||||
|
enum StatusEditChangeType{
|
||||||
|
TEXT_CHANGED,
|
||||||
|
SPOILER_ADDED,
|
||||||
|
SPOILER_REMOVED,
|
||||||
|
SPOILER_CHANGED,
|
||||||
|
POLL_ADDED,
|
||||||
|
POLL_REMOVED,
|
||||||
|
POLL_CHANGED,
|
||||||
|
MEDIA_ADDED,
|
||||||
|
MEDIA_REMOVED,
|
||||||
|
MEDIA_REORDERED,
|
||||||
|
MARKED_SENSITIVE,
|
||||||
|
MARKED_NOT_SENSITIVE
|
||||||
|
}
|
||||||
|
EnumSet<StatusEditChangeType> changes=EnumSet.noneOf(StatusEditChangeType.class);
|
||||||
|
Status prev=data.get(idx+1);
|
||||||
|
|
||||||
|
if(!Objects.equals(s.content, prev.content)){
|
||||||
|
changes.add(StatusEditChangeType.TEXT_CHANGED);
|
||||||
|
}
|
||||||
|
if(!Objects.equals(s.spoilerText, prev.spoilerText)){
|
||||||
|
if(s.spoilerText==null){
|
||||||
|
changes.add(StatusEditChangeType.SPOILER_REMOVED);
|
||||||
|
}else if(prev.spoilerText==null){
|
||||||
|
changes.add(StatusEditChangeType.SPOILER_ADDED);
|
||||||
|
}else{
|
||||||
|
changes.add(StatusEditChangeType.SPOILER_CHANGED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(s.poll!=null || prev.poll!=null){
|
||||||
|
if(s.poll==null){
|
||||||
|
changes.add(StatusEditChangeType.POLL_REMOVED);
|
||||||
|
}else if(prev.poll==null){
|
||||||
|
changes.add(StatusEditChangeType.POLL_ADDED);
|
||||||
|
}else if(!s.poll.id.equals(prev.poll.id)){
|
||||||
|
changes.add(StatusEditChangeType.POLL_CHANGED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<String> newAttachmentIDs=s.mediaAttachments.stream().map(att->att.id).collect(Collectors.toList());
|
||||||
|
List<String> prevAttachmentIDs=s.mediaAttachments.stream().map(att->att.id).collect(Collectors.toList());
|
||||||
|
boolean addedOrRemoved=false;
|
||||||
|
if(!newAttachmentIDs.containsAll(prevAttachmentIDs)){
|
||||||
|
changes.add(StatusEditChangeType.MEDIA_REMOVED);
|
||||||
|
addedOrRemoved=true;
|
||||||
|
}
|
||||||
|
if(!prevAttachmentIDs.containsAll(newAttachmentIDs)){
|
||||||
|
changes.add(StatusEditChangeType.MEDIA_ADDED);
|
||||||
|
addedOrRemoved=true;
|
||||||
|
}
|
||||||
|
if(!addedOrRemoved && !newAttachmentIDs.equals(prevAttachmentIDs)){
|
||||||
|
changes.add(StatusEditChangeType.MEDIA_REORDERED);
|
||||||
|
}
|
||||||
|
if(s.sensitive && !prev.sensitive){
|
||||||
|
changes.add(StatusEditChangeType.MARKED_SENSITIVE);
|
||||||
|
}else if(prev.sensitive && !s.sensitive){
|
||||||
|
changes.add(StatusEditChangeType.MARKED_NOT_SENSITIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(changes.size()==1){
|
||||||
|
action=getString(switch(changes.iterator().next()){
|
||||||
|
case TEXT_CHANGED -> R.string.edit_text_edited;
|
||||||
|
case SPOILER_ADDED -> R.string.edit_spoiler_added;
|
||||||
|
case SPOILER_REMOVED -> R.string.edit_spoiler_removed;
|
||||||
|
case SPOILER_CHANGED -> R.string.edit_spoiler_edited;
|
||||||
|
case POLL_ADDED -> R.string.edit_poll_added;
|
||||||
|
case POLL_REMOVED -> R.string.edit_poll_removed;
|
||||||
|
case POLL_CHANGED -> R.string.edit_poll_edited;
|
||||||
|
case MEDIA_ADDED -> R.string.edit_media_added;
|
||||||
|
case MEDIA_REMOVED -> R.string.edit_media_removed;
|
||||||
|
case MEDIA_REORDERED -> R.string.edit_media_reordered;
|
||||||
|
case MARKED_SENSITIVE -> R.string.edit_marked_sensitive;
|
||||||
|
case MARKED_NOT_SENSITIVE -> R.string.edit_marked_not_sensitive;
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
action=getString(R.string.edit_multiple_changed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
items.add(0, new ReblogOrReplyLineStatusDisplayItem(s.id, this, action+" · "+date, Collections.emptyList(), 0));
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewCreated(View view, Bundle savedInstanceState){
|
||||||
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
list.addItemDecoration(new InsetStatusItemDecoration(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isItemEnabled(String id){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -37,6 +37,7 @@ public class Status extends BaseModel implements DisplayItemsParent{
|
|||||||
public int reblogsCount;
|
public int reblogsCount;
|
||||||
public int favouritesCount;
|
public int favouritesCount;
|
||||||
public int repliesCount;
|
public int repliesCount;
|
||||||
|
public Instant editedAt;
|
||||||
|
|
||||||
public String url;
|
public String url;
|
||||||
public String inReplyToId;
|
public String inReplyToId;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package org.joinmastodon.android.ui.displayitems;
|
package org.joinmastodon.android.ui.displayitems;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.SpannableStringBuilder;
|
import android.text.SpannableStringBuilder;
|
||||||
@ -12,6 +13,7 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
||||||
|
import org.joinmastodon.android.fragments.StatusEditHistoryFragment;
|
||||||
import org.joinmastodon.android.fragments.account_list.StatusFavoritesListFragment;
|
import org.joinmastodon.android.fragments.account_list.StatusFavoritesListFragment;
|
||||||
import org.joinmastodon.android.fragments.account_list.StatusReblogsListFragment;
|
import org.joinmastodon.android.fragments.account_list.StatusReblogsListFragment;
|
||||||
import org.joinmastodon.android.fragments.account_list.StatusRelatedAccountListFragment;
|
import org.joinmastodon.android.fragments.account_list.StatusRelatedAccountListFragment;
|
||||||
@ -43,39 +45,35 @@ public class ExtendedFooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class Holder extends StatusDisplayItem.Holder<ExtendedFooterStatusDisplayItem>{
|
public static class Holder extends StatusDisplayItem.Holder<ExtendedFooterStatusDisplayItem>{
|
||||||
private final TextView reblogs, favorites, time;
|
private final TextView time, favoritesCount, reblogsCount, lastEditTime;
|
||||||
private final View buttonsView;
|
private final View favorites, reblogs, editHistory;
|
||||||
|
|
||||||
public Holder(Context context, ViewGroup parent){
|
public Holder(Context context, ViewGroup parent){
|
||||||
super(context, R.layout.display_item_extended_footer, parent);
|
super(context, R.layout.display_item_extended_footer, parent);
|
||||||
reblogs=findViewById(R.id.reblogs);
|
reblogs=findViewById(R.id.reblogs);
|
||||||
favorites=findViewById(R.id.favorites);
|
favorites=findViewById(R.id.favorites);
|
||||||
|
editHistory=findViewById(R.id.edit_history);
|
||||||
time=findViewById(R.id.timestamp);
|
time=findViewById(R.id.timestamp);
|
||||||
buttonsView=findViewById(R.id.button_bar);
|
favoritesCount=findViewById(R.id.favorites_count);
|
||||||
|
reblogsCount=findViewById(R.id.reblogs_count);
|
||||||
|
lastEditTime=findViewById(R.id.last_edited);
|
||||||
|
|
||||||
reblogs.setOnClickListener(v->startAccountListFragment(StatusReblogsListFragment.class));
|
reblogs.setOnClickListener(v->startAccountListFragment(StatusReblogsListFragment.class));
|
||||||
favorites.setOnClickListener(v->startAccountListFragment(StatusFavoritesListFragment.class));
|
favorites.setOnClickListener(v->startAccountListFragment(StatusFavoritesListFragment.class));
|
||||||
|
editHistory.setOnClickListener(v->startEditHistoryFragment());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("DefaultLocale")
|
||||||
@Override
|
@Override
|
||||||
public void onBind(ExtendedFooterStatusDisplayItem item){
|
public void onBind(ExtendedFooterStatusDisplayItem item){
|
||||||
Status s=item.status;
|
Status s=item.status;
|
||||||
if(s.favouritesCount>0){
|
favoritesCount.setText(String.format("%,d", s.favouritesCount));
|
||||||
favorites.setVisibility(View.VISIBLE);
|
reblogsCount.setText(String.format("%,d", s.reblogsCount));
|
||||||
favorites.setText(getFormattedPlural(R.plurals.x_favorites, s.favouritesCount));
|
if(s.editedAt!=null){
|
||||||
|
editHistory.setVisibility(View.VISIBLE);
|
||||||
|
lastEditTime.setText(item.parentFragment.getString(R.string.last_edit_at_x, UiUtils.formatRelativeTimestampAsMinutesAgo(itemView.getContext(), s.editedAt)));
|
||||||
}else{
|
}else{
|
||||||
favorites.setVisibility(View.GONE);
|
editHistory.setVisibility(View.GONE);
|
||||||
}
|
|
||||||
if(s.reblogsCount>0){
|
|
||||||
reblogs.setVisibility(View.VISIBLE);
|
|
||||||
reblogs.setText(getFormattedPlural(R.plurals.x_reblogs, s.reblogsCount));
|
|
||||||
}else{
|
|
||||||
reblogs.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
if(s.favouritesCount==0 && s.reblogsCount==0){
|
|
||||||
buttonsView.setVisibility(View.GONE);
|
|
||||||
}else{
|
|
||||||
buttonsView.setVisibility(View.VISIBLE);
|
|
||||||
}
|
}
|
||||||
String timeStr=TIME_FORMATTER.format(item.status.createdAt.atZone(ZoneId.systemDefault()));
|
String timeStr=TIME_FORMATTER.format(item.status.createdAt.atZone(ZoneId.systemDefault()));
|
||||||
if(item.status.application!=null && !TextUtils.isEmpty(item.status.application.name)){
|
if(item.status.application!=null && !TextUtils.isEmpty(item.status.application.name)){
|
||||||
@ -108,5 +106,12 @@ public class ExtendedFooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
args.putParcelable("status", Parcels.wrap(item.status));
|
args.putParcelable("status", Parcels.wrap(item.status));
|
||||||
Nav.go(item.parentFragment.getActivity(), cls, args);
|
Nav.go(item.parentFragment.getActivity(), cls, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void startEditHistoryFragment(){
|
||||||
|
Bundle args=new Bundle();
|
||||||
|
args.putString("account", item.parentFragment.getAccountID());
|
||||||
|
args.putString("id", item.status.id);
|
||||||
|
Nav.go(item.parentFragment.getActivity(), StatusEditHistoryFragment.class, args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,7 +175,10 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
public void onBind(HeaderStatusDisplayItem item){
|
public void onBind(HeaderStatusDisplayItem item){
|
||||||
name.setText(item.parsedName);
|
name.setText(item.parsedName);
|
||||||
username.setText('@'+item.user.acct);
|
username.setText('@'+item.user.acct);
|
||||||
timestamp.setText(UiUtils.formatRelativeTimestamp(itemView.getContext(), item.createdAt));
|
if(item.status==null || item.status.editedAt==null)
|
||||||
|
timestamp.setText(UiUtils.formatRelativeTimestamp(itemView.getContext(), item.createdAt));
|
||||||
|
else
|
||||||
|
timestamp.setText(item.parentFragment.getString(R.string.edited_timestamp, UiUtils.formatRelativeTimestamp(itemView.getContext(), item.status.editedAt)));
|
||||||
visibility.setVisibility(item.hasVisibilityToggle && !item.inset ? View.VISIBLE : View.GONE);
|
visibility.setVisibility(item.hasVisibilityToggle && !item.inset ? View.VISIBLE : View.GONE);
|
||||||
if(item.hasVisibilityToggle){
|
if(item.hasVisibilityToggle){
|
||||||
visibility.setImageResource(item.status.spoilerRevealed ? R.drawable.ic_visibility_off : R.drawable.ic_visibility);
|
visibility.setImageResource(item.status.spoilerRevealed ? R.drawable.ic_visibility_off : R.drawable.ic_visibility);
|
||||||
|
@ -0,0 +1,116 @@
|
|||||||
|
package org.joinmastodon.android.ui.utils;
|
||||||
|
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.graphics.RectF;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.R;
|
||||||
|
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
||||||
|
import org.joinmastodon.android.fragments.NotificationsListFragment;
|
||||||
|
import org.joinmastodon.android.ui.PhotoLayoutHelper;
|
||||||
|
import org.joinmastodon.android.ui.displayitems.ImageStatusDisplayItem;
|
||||||
|
import org.joinmastodon.android.ui.displayitems.LinkCardStatusDisplayItem;
|
||||||
|
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import me.grishka.appkit.utils.V;
|
||||||
|
|
||||||
|
public class InsetStatusItemDecoration extends RecyclerView.ItemDecoration{
|
||||||
|
private final BaseStatusListFragment<?> listFragment;
|
||||||
|
private Paint paint=new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
private int bgColor;
|
||||||
|
private int borderColor;
|
||||||
|
private RectF rect=new RectF();
|
||||||
|
|
||||||
|
public InsetStatusItemDecoration(BaseStatusListFragment<?> listFragment){
|
||||||
|
this.listFragment=listFragment;
|
||||||
|
bgColor=UiUtils.getThemeColor(listFragment.getActivity(), android.R.attr.colorBackground);
|
||||||
|
borderColor=UiUtils.getThemeColor(listFragment.getActivity(), R.attr.colorPollVoted);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state){
|
||||||
|
List<StatusDisplayItem> displayItems=listFragment.getDisplayItems();
|
||||||
|
int pos=0;
|
||||||
|
for(int i=0; i<parent.getChildCount(); i++){
|
||||||
|
View child=parent.getChildAt(i);
|
||||||
|
RecyclerView.ViewHolder holder=parent.getChildViewHolder(child);
|
||||||
|
pos=holder.getAbsoluteAdapterPosition();
|
||||||
|
boolean inset=(holder instanceof StatusDisplayItem.Holder<?> sdi) && sdi.getItem().inset;
|
||||||
|
if(inset){
|
||||||
|
if(rect.isEmpty()){
|
||||||
|
rect.set(child.getX(), i==0 && pos>0 && displayItems.get(pos-1).inset ? V.dp(-10) : child.getY(), child.getX()+child.getWidth(), child.getY()+child.getHeight());
|
||||||
|
}else{
|
||||||
|
rect.bottom=Math.max(rect.bottom, child.getY()+child.getHeight());
|
||||||
|
}
|
||||||
|
}else if(!rect.isEmpty()){
|
||||||
|
drawInsetBackground(parent, c);
|
||||||
|
rect.setEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!rect.isEmpty()){
|
||||||
|
if(pos<displayItems.size()-1 && displayItems.get(pos+1).inset){
|
||||||
|
rect.bottom=parent.getHeight()+V.dp(10);
|
||||||
|
}
|
||||||
|
drawInsetBackground(parent, c);
|
||||||
|
rect.setEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawInsetBackground(RecyclerView list, Canvas c){
|
||||||
|
paint.setStyle(Paint.Style.FILL);
|
||||||
|
paint.setColor(bgColor);
|
||||||
|
rect.left=V.dp(12);
|
||||||
|
rect.right=list.getWidth()-V.dp(12);
|
||||||
|
rect.inset(V.dp(4), V.dp(4));
|
||||||
|
c.drawRoundRect(rect, V.dp(4), V.dp(4), paint);
|
||||||
|
paint.setStyle(Paint.Style.STROKE);
|
||||||
|
paint.setStrokeWidth(V.dp(1));
|
||||||
|
paint.setColor(borderColor);
|
||||||
|
rect.inset(paint.getStrokeWidth()/2f, paint.getStrokeWidth()/2f);
|
||||||
|
c.drawRoundRect(rect, V.dp(4), V.dp(4), paint);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state){
|
||||||
|
List<StatusDisplayItem> displayItems=listFragment.getDisplayItems();
|
||||||
|
RecyclerView.ViewHolder holder=parent.getChildViewHolder(view);
|
||||||
|
if(holder instanceof StatusDisplayItem.Holder<?> sdi){
|
||||||
|
boolean inset=sdi.getItem().inset;
|
||||||
|
int pos=holder.getAbsoluteAdapterPosition();
|
||||||
|
if(inset){
|
||||||
|
boolean topSiblingInset=pos>0 && displayItems.get(pos-1).inset;
|
||||||
|
boolean bottomSiblingInset=pos<displayItems.size()-1 && displayItems.get(pos+1).inset;
|
||||||
|
int pad;
|
||||||
|
if(holder instanceof ImageStatusDisplayItem.Holder || holder instanceof LinkCardStatusDisplayItem.Holder)
|
||||||
|
pad=V.dp(16);
|
||||||
|
else
|
||||||
|
pad=V.dp(12);
|
||||||
|
boolean insetLeft=true, insetRight=true;
|
||||||
|
if(holder instanceof ImageStatusDisplayItem.Holder<?> img){
|
||||||
|
PhotoLayoutHelper.TiledLayoutResult layout=img.getItem().tiledLayout;
|
||||||
|
PhotoLayoutHelper.TiledLayoutResult.Tile tile=img.getItem().thisTile;
|
||||||
|
// only inset those items that are on the edges of the layout
|
||||||
|
insetLeft=tile.startCol==0;
|
||||||
|
insetRight=tile.startCol+tile.colSpan==layout.columnSizes.length;
|
||||||
|
// inset all items in the bottom row
|
||||||
|
if(tile.startRow+tile.rowSpan==layout.rowSizes.length)
|
||||||
|
bottomSiblingInset=false;
|
||||||
|
}
|
||||||
|
if(insetLeft)
|
||||||
|
outRect.left=pad;
|
||||||
|
if(insetRight)
|
||||||
|
outRect.right=pad;
|
||||||
|
if(!topSiblingInset)
|
||||||
|
outRect.top=pad;
|
||||||
|
if(!bottomSiblingInset)
|
||||||
|
outRect.bottom=pad;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -62,6 +62,7 @@ import java.time.Instant;
|
|||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.format.FormatStyle;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -85,6 +86,7 @@ import okhttp3.MediaType;
|
|||||||
public class UiUtils{
|
public class UiUtils{
|
||||||
private static Handler mainHandler=new Handler(Looper.getMainLooper());
|
private static Handler mainHandler=new Handler(Looper.getMainLooper());
|
||||||
private static final DateTimeFormatter DATE_FORMATTER_SHORT_WITH_YEAR=DateTimeFormatter.ofPattern("d MMM uuuu"), DATE_FORMATTER_SHORT=DateTimeFormatter.ofPattern("d MMM");
|
private static final DateTimeFormatter DATE_FORMATTER_SHORT_WITH_YEAR=DateTimeFormatter.ofPattern("d MMM uuuu"), DATE_FORMATTER_SHORT=DateTimeFormatter.ofPattern("d MMM");
|
||||||
|
public static final DateTimeFormatter DATE_TIME_FORMATTER=DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG, FormatStyle.SHORT);
|
||||||
|
|
||||||
private UiUtils(){}
|
private UiUtils(){}
|
||||||
|
|
||||||
@ -129,6 +131,23 @@ public class UiUtils{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String formatRelativeTimestampAsMinutesAgo(Context context, Instant instant){
|
||||||
|
long t=instant.toEpochMilli();
|
||||||
|
long now=System.currentTimeMillis();
|
||||||
|
long diff=now-t;
|
||||||
|
if(diff<1000L){
|
||||||
|
return context.getString(R.string.time_just_now);
|
||||||
|
}else if(diff<60_000L){
|
||||||
|
int secs=(int)(diff/1000L);
|
||||||
|
return context.getResources().getQuantityString(R.plurals.x_seconds_ago, secs, secs);
|
||||||
|
}else if(diff<3600_000L){
|
||||||
|
int mins=(int)(diff/60_000L);
|
||||||
|
return context.getResources().getQuantityString(R.plurals.x_minutes_ago, mins, mins);
|
||||||
|
}else{
|
||||||
|
return DATE_TIME_FORMATTER.format(instant.atZone(ZoneId.systemDefault()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static String formatTimeLeft(Context context, Instant instant){
|
public static String formatTimeLeft(Context context, Instant instant){
|
||||||
long t=instant.toEpochMilli();
|
long t=instant.toEpochMilli();
|
||||||
long now=System.currentTimeMillis();
|
long now=System.currentTimeMillis();
|
||||||
|
@ -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="M21.03 2.97c1.398 1.397 1.398 3.663 0 5.06L9.062 20c-0.277 0.277-0.621 0.477-0.999 0.58l-5.116 1.395c-0.56 0.153-1.073-0.361-0.92-0.921l1.395-5.116c0.103-0.377 0.302-0.722 0.58-0.999L15.97 2.97c1.397-1.398 3.663-1.398 5.06 0zM15 6.06L5.062 16c-0.092 0.092-0.159 0.207-0.193 0.333l-1.05 3.85 3.85-1.05C7.793 19.096 7.908 19.03 8 18.938L17.94 9 15 6.06zm2.03-2.03L16.06 5 19 7.94l0.97-0.97c0.811-0.812 0.811-2.128 0-2.94-0.812-0.811-2.128-0.811-2.94 0z" android:fillColor="@color/fluent_default_icon_tint"/>
|
||||||
|
</vector>
|
@ -2,49 +2,146 @@
|
|||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:padding="8dp"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content">
|
||||||
android:background="?colorBackgroundLightest">
|
|
||||||
|
|
||||||
<org.joinmastodon.android.ui.views.AutoOrientationLinearLayout
|
<RelativeLayout
|
||||||
android:id="@+id/button_bar"
|
android:id="@+id/reblogs"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="64dp"
|
||||||
|
android:paddingLeft="16dp"
|
||||||
|
android:paddingRight="16dp"
|
||||||
|
android:paddingTop="12dp"
|
||||||
|
android:paddingBottom="12dp"
|
||||||
|
android:background="?android:selectableItemBackground">
|
||||||
|
|
||||||
<Button
|
<ImageView
|
||||||
android:id="@+id/reblogs"
|
android:id="@+id/icon"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:src="@drawable/ic_fluent_arrow_repeat_all_24_regular"
|
||||||
|
android:tint="?android:textColorSecondary"
|
||||||
|
android:importantForAccessibility="no"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center"
|
android:layout_marginStart="32dp"
|
||||||
android:padding="8dp"
|
android:layout_toEndOf="@id/icon"
|
||||||
android:textSize="14sp"
|
android:minHeight="22dp"
|
||||||
android:minHeight="36dp"
|
android:singleLine="true"
|
||||||
android:textColor="?android:textColorSecondary"
|
android:text="@string/post_info_reblogs"
|
||||||
android:background="@drawable/bg_text_button"
|
android:textAppearance="@style/m3_body_large" />
|
||||||
android:fontFamily="sans-serif"
|
|
||||||
tools:text="4 reblogs"/>
|
|
||||||
|
|
||||||
<Button
|
<TextView
|
||||||
android:id="@+id/favorites"
|
android:id="@+id/reblogs_count"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center"
|
android:layout_below="@id/title"
|
||||||
android:padding="8dp"
|
android:layout_alignStart="@id/title"
|
||||||
android:textSize="14sp"
|
android:singleLine="true"
|
||||||
android:minHeight="36dp"
|
android:textAppearance="@style/m3_body_medium"
|
||||||
android:textColor="?android:textColorSecondary"
|
android:textColor="?android:textColorSecondary"
|
||||||
android:background="@drawable/bg_text_button"
|
tools:text="123 456"/>
|
||||||
android:fontFamily="sans-serif"
|
|
||||||
tools:text="12 favorites"/>
|
|
||||||
|
|
||||||
</org.joinmastodon.android.ui.views.AutoOrientationLinearLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/favorites"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="64dp"
|
||||||
|
android:paddingLeft="16dp"
|
||||||
|
android:paddingRight="16dp"
|
||||||
|
android:paddingTop="12dp"
|
||||||
|
android:paddingBottom="12dp"
|
||||||
|
android:background="?android:selectableItemBackground">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/icon"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:src="@drawable/ic_fluent_star_24_regular"
|
||||||
|
android:tint="?android:textColorSecondary"
|
||||||
|
android:importantForAccessibility="no"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="32dp"
|
||||||
|
android:layout_toEndOf="@id/icon"
|
||||||
|
android:minHeight="22dp"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:text="@string/post_info_favorites"
|
||||||
|
android:textAppearance="@style/m3_body_large" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/favorites_count"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/title"
|
||||||
|
android:layout_alignStart="@id/title"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textAppearance="@style/m3_body_medium"
|
||||||
|
android:textColor="?android:textColorSecondary"
|
||||||
|
tools:text="123 456"/>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/edit_history"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="64dp"
|
||||||
|
android:paddingLeft="16dp"
|
||||||
|
android:paddingRight="16dp"
|
||||||
|
android:paddingTop="12dp"
|
||||||
|
android:paddingBottom="12dp"
|
||||||
|
android:background="?android:selectableItemBackground">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/icon"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:src="@drawable/ic_fluent_edit_24_regular"
|
||||||
|
android:tint="?android:textColorSecondary"
|
||||||
|
android:importantForAccessibility="no"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="32dp"
|
||||||
|
android:layout_toEndOf="@id/icon"
|
||||||
|
android:minHeight="22dp"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:text="@string/edit_history"
|
||||||
|
android:textAppearance="@style/m3_body_large" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/last_edited"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/title"
|
||||||
|
android:layout_alignStart="@id/title"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textAppearance="@style/m3_body_medium"
|
||||||
|
android:textColor="?android:textColorSecondary"
|
||||||
|
tools:text="123 456"/>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/timestamp"
|
android:id="@+id/timestamp"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="16dp"
|
||||||
android:minHeight="20dp"
|
android:minHeight="20dp"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
|
@ -340,4 +340,32 @@
|
|||||||
</plurals>
|
</plurals>
|
||||||
<string name="timestamp_via_app">%1$s via %2$s</string>
|
<string name="timestamp_via_app">%1$s via %2$s</string>
|
||||||
<string name="time_now">now</string>
|
<string name="time_now">now</string>
|
||||||
|
<string name="post_info_reblogs">Reblogs</string>
|
||||||
|
<string name="post_info_favorites">Favorites</string>
|
||||||
|
<string name="edit_history">Edit history</string>
|
||||||
|
<string name="last_edit_at_x">Last edit %s</string>
|
||||||
|
<string name="time_just_now">just now</string>
|
||||||
|
<plurals name="x_seconds_ago">
|
||||||
|
<item quantity="one">%d second ago</item>
|
||||||
|
<item quantity="other">%d seconds ago</item>
|
||||||
|
</plurals>
|
||||||
|
<plurals name="x_minutes_ago">
|
||||||
|
<item quantity="one">%d minute ago</item>
|
||||||
|
<item quantity="other">%d minutes ago</item>
|
||||||
|
</plurals>
|
||||||
|
<string name="edited_timestamp">edited %s</string>
|
||||||
|
<string name="edit_original_post">Original post</string>
|
||||||
|
<string name="edit_text_edited">Text edited</string>
|
||||||
|
<string name="edit_spoiler_added">Content warning added</string>
|
||||||
|
<string name="edit_spoiler_edited">Content warning edited</string>
|
||||||
|
<string name="edit_spoiler_removed">Content warning removed</string>
|
||||||
|
<string name="edit_poll_added">Poll added</string>
|
||||||
|
<string name="edit_poll_edited">Poll edited</string>
|
||||||
|
<string name="edit_poll_removed">Poll removed</string>
|
||||||
|
<string name="edit_media_added">Media added</string>
|
||||||
|
<string name="edit_media_removed">Media removed</string>
|
||||||
|
<string name="edit_media_reordered">Media reordered</string>
|
||||||
|
<string name="edit_marked_sensitive">Marked sensitive</string>
|
||||||
|
<string name="edit_marked_not_sensitive">Marked not sensitive</string>
|
||||||
|
<string name="edit_multiple_changed">Post edited</string>
|
||||||
</resources>
|
</resources>
|
Loading…
x
Reference in New Issue
Block a user