diff --git a/mastodon/src/main/java/org/joinmastodon/android/model/Card.java b/mastodon/src/main/java/org/joinmastodon/android/model/Card.java index 0c98eb1a..56260340 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/model/Card.java +++ b/mastodon/src/main/java/org/joinmastodon/android/model/Card.java @@ -16,6 +16,8 @@ public class Card extends BaseModel{ @RequiredField public String url; @RequiredField + public String title; + @RequiredField public String description; @RequiredField public Type type; @@ -46,6 +48,7 @@ public class Card extends BaseModel{ public String toString(){ return "Card{"+ "url='"+url+'\''+ + ", title='"+title+'\''+ ", description='"+description+'\''+ ", type="+type+ ", authorName='"+authorName+'\''+ diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/LinkCardStatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/LinkCardStatusDisplayItem.java new file mode 100644 index 00000000..c7985189 --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/LinkCardStatusDisplayItem.java @@ -0,0 +1,101 @@ +package org.joinmastodon.android.ui.displayitems; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.text.TextUtils; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import org.joinmastodon.android.R; +import org.joinmastodon.android.fragments.BaseStatusListFragment; +import org.joinmastodon.android.model.Card; +import org.joinmastodon.android.model.Status; +import org.joinmastodon.android.ui.drawables.BlurhashCrossfadeDrawable; +import org.joinmastodon.android.ui.utils.UiUtils; + +import me.grishka.appkit.imageloader.ImageLoaderViewHolder; +import me.grishka.appkit.imageloader.requests.ImageLoaderRequest; +import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest; + +public class LinkCardStatusDisplayItem extends StatusDisplayItem{ + private final Status status; + private final UrlImageLoaderRequest imgRequest; + + public LinkCardStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, Status status){ + super(parentID, parentFragment); + this.status=status; + if(status.card.image!=null) + imgRequest=new UrlImageLoaderRequest(status.card.image, 1000, 1000); + else + imgRequest=null; + } + + @Override + public Type getType(){ + return Type.CARD; + } + + @Override + public int getImageCount(){ + return imgRequest==null ? 0 : 1; + } + + @Override + public ImageLoaderRequest getImageRequest(int index){ + return imgRequest; + } + + public static class Holder extends StatusDisplayItem.Holder implements ImageLoaderViewHolder{ + private final TextView title, description, domain; + private final ImageView photo; + private BlurhashCrossfadeDrawable crossfadeDrawable=new BlurhashCrossfadeDrawable(); + private boolean didClear; + + public Holder(Context context, ViewGroup parent){ + super(context, R.layout.display_item_link_card, parent); + title=findViewById(R.id.title); + description=findViewById(R.id.description); + domain=findViewById(R.id.domain); + photo=findViewById(R.id.photo); + findViewById(R.id.inner).setOnClickListener(this::onClick); + } + + @Override + public void onBind(LinkCardStatusDisplayItem item){ + Card card=item.status.card; + title.setText(card.title); + description.setText(card.description); + description.setVisibility(TextUtils.isEmpty(card.description) ? View.GONE : View.VISIBLE); + domain.setText(Uri.parse(card.url).getHost()); + + photo.setImageDrawable(null); + if(item.imgRequest!=null){ + crossfadeDrawable.setSize(card.width, card.height); + crossfadeDrawable.setBlurhashDrawable(card.blurhashPlaceholder); + crossfadeDrawable.setCrossfadeAlpha(item.status.spoilerRevealed ? 0f : 1f); + photo.setImageDrawable(crossfadeDrawable); + didClear=false; + } + } + + @Override + public void setImage(int index, Drawable drawable){ + crossfadeDrawable.setImageDrawable(drawable); + if(didClear && item.status.spoilerRevealed) + crossfadeDrawable.animateAlpha(0f); + } + + @Override + public void clearImage(int index){ + crossfadeDrawable.setCrossfadeAlpha(1f); + didClear=true; + } + + private void onClick(View v){ + UiUtils.launchWebBrowser(itemView.getContext(), item.status.card.url); + } + } +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java index fd0cfff4..2ba9805b 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java @@ -55,6 +55,7 @@ public abstract class StatusDisplayItem{ case VIDEO -> new VideoStatusDisplayItem.Holder(activity, parent); case POLL_OPTION -> new PollOptionStatusDisplayItem.Holder(activity, parent); case POLL_FOOTER -> new PollFooterStatusDisplayItem.Holder(activity, parent); + case CARD -> new LinkCardStatusDisplayItem.Holder(activity, parent); case FOOTER -> new FooterStatusDisplayItem.Holder(activity, parent); default -> throw new UnsupportedOperationException(); }; @@ -96,6 +97,9 @@ public abstract class StatusDisplayItem{ if(statusForContent.poll!=null){ buildPollItems(parentID, fragment, statusForContent.poll, items); } + if(statusForContent.card!=null){ + items.add(new LinkCardStatusDisplayItem(parentID, fragment, statusForContent)); + } items.add(new FooterStatusDisplayItem(parentID, fragment, statusForContent, accountID)); return items; } diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/views/MaxWidthFrameLayout.java b/mastodon/src/main/java/org/joinmastodon/android/ui/views/MaxWidthFrameLayout.java new file mode 100644 index 00000000..364f030f --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/views/MaxWidthFrameLayout.java @@ -0,0 +1,43 @@ +package org.joinmastodon.android.ui.views; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.widget.FrameLayout; + +import org.joinmastodon.android.R; + +public class MaxWidthFrameLayout extends FrameLayout{ + private int maxWidth; + + public MaxWidthFrameLayout(Context context){ + this(context, null); + } + + public MaxWidthFrameLayout(Context context, AttributeSet attrs){ + this(context, attrs, 0); + } + + public MaxWidthFrameLayout(Context context, AttributeSet attrs, int defStyle){ + super(context, attrs, defStyle); + TypedArray ta=context.obtainStyledAttributes(attrs, R.styleable.MaxWidthFrameLayout); + maxWidth=ta.getDimensionPixelSize(R.styleable.MaxWidthFrameLayout_android_maxWidth, Integer.MAX_VALUE); + ta.recycle(); + } + + public int getMaxWidth(){ + return maxWidth; + } + + public void setMaxWidth(int maxWidth){ + this.maxWidth=maxWidth; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){ + if(MeasureSpec.getSize(widthMeasureSpec)>maxWidth){ + widthMeasureSpec=maxWidth | MeasureSpec.getMode(widthMeasureSpec); + } + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/views/TabBar.java b/mastodon/src/main/java/org/joinmastodon/android/ui/views/TabBar.java index ad86845d..8f2b83b5 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/views/TabBar.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/views/TabBar.java @@ -43,7 +43,7 @@ public class TabBar extends LinearLayout{ } private void onChildClick(View v){ - listener.accept(selectedTabID); + listener.accept(v.getId()); if(v.getId()==selectedTabID) return; findViewById(selectedTabID).setSelected(false); diff --git a/mastodon/src/main/res/color/window_bg_alpha95.xml b/mastodon/src/main/res/color/window_bg_alpha95.xml new file mode 100644 index 00000000..fe4fa60f --- /dev/null +++ b/mastodon/src/main/res/color/window_bg_alpha95.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/mastodon/src/main/res/drawable/window_bg_alpha95.xml b/mastodon/src/main/res/drawable/window_bg_alpha95.xml new file mode 100644 index 00000000..9cbb77ea --- /dev/null +++ b/mastodon/src/main/res/drawable/window_bg_alpha95.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/mastodon/src/main/res/layout/display_item_link_card.xml b/mastodon/src/main/res/layout/display_item_link_card.xml new file mode 100644 index 00000000..34fa994f --- /dev/null +++ b/mastodon/src/main/res/layout/display_item_link_card.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/mastodon/src/main/res/values/attrs.xml b/mastodon/src/main/res/values/attrs.xml index 5d9e40c0..31fba285 100644 --- a/mastodon/src/main/res/values/attrs.xml +++ b/mastodon/src/main/res/values/attrs.xml @@ -7,5 +7,10 @@ + + + + + \ No newline at end of file diff --git a/mastodon/src/main/res/values/styles.xml b/mastodon/src/main/res/values/styles.xml index 6ac7f745..f5965ec9 100644 --- a/mastodon/src/main/res/values/styles.xml +++ b/mastodon/src/main/res/values/styles.xml @@ -6,6 +6,7 @@ false @drawable/ic_fluent_arrow_left_24_regular false + ?colorWindowBackground @style/Widget.Mastodon.Button.Primary_DarkOnLight @style/Widget.Mastodon.Button.Secondary_DarkOnLight @@ -19,7 +20,7 @@ @color/gray_50 @color/gray_25 @color/gray_900 - @color/white + @color/white @color/actionbar_bg @color/navigation_bar_bg @style/Theme.Mastodon.Toolbar @@ -37,6 +38,7 @@ false @drawable/ic_fluent_arrow_left_24_regular false + ?colorWindowBackground @style/Widget.Mastodon.Button.Primary_LightOnDark @style/Widget.Mastodon.Button.Secondary_LightOnDark @@ -50,7 +52,7 @@ @color/gray_700 @color/gray_700 @color/gray_25 - @color/gray_800 + @color/gray_800 @color/actionbar_bg_dark @color/actionbar_bg_dark @style/Theme.Mastodon.Toolbar.Dark