Link cards
This commit is contained in:
parent
d25b7e67b8
commit
658415fd89
|
@ -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+'\''+
|
||||
|
|
|
@ -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<LinkCardStatusDisplayItem> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="?colorWindowBackground" android:alpha="0.95"/>
|
||||
</selector>
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/window_bg_alpha95"/>
|
||||
</shape>
|
|
@ -0,0 +1,54 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<org.joinmastodon.android.ui.views.MaxWidthFrameLayout
|
||||
android:id="@+id/inner"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="250dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:foreground="?android:selectableItemBackground"
|
||||
android:maxWidth="400dp">
|
||||
<ImageView
|
||||
android:id="@+id/photo"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="centerCrop"
|
||||
tools:src="#0f0"/>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:padding="8dp"
|
||||
android:orientation="vertical"
|
||||
android:background="@drawable/window_bg_alpha95">
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/m3_body_large"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
tools:text="Link title"/>
|
||||
<TextView
|
||||
android:id="@+id/description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="2"
|
||||
android:ellipsize="end"
|
||||
android:textAppearance="@style/m3_body_medium"
|
||||
tools:text="Link description"/>
|
||||
<TextView
|
||||
android:id="@+id/domain"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/m3_body_medium"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
tools:text="example.com"/>
|
||||
</LinearLayout>
|
||||
</org.joinmastodon.android.ui.views.MaxWidthFrameLayout>
|
||||
|
||||
</FrameLayout>
|
|
@ -7,5 +7,10 @@
|
|||
<attr name="colorDarkIcon" format="color"/>
|
||||
<attr name="colorPollMostVoted" format="color"/>
|
||||
<attr name="colorPollVoted" format="color"/>
|
||||
<attr name="colorWindowBackground" format="color"/>
|
||||
<attr name="secondaryButtonStyle" format="reference"/>
|
||||
|
||||
<declare-styleable name="MaxWidthFrameLayout">
|
||||
<attr name="android:maxWidth" format="dimension"/>
|
||||
</declare-styleable>
|
||||
</resources>
|
|
@ -6,6 +6,7 @@
|
|||
<item name="android:enforceStatusBarContrast" tools:ignore="NewApi">false</item>
|
||||
<item name="appkitBackDrawable">@drawable/ic_fluent_arrow_left_24_regular</item>
|
||||
<item name="android:splitMotionEvents">false</item>
|
||||
<item name="android:windowBackground">?colorWindowBackground</item>
|
||||
|
||||
<item name="android:buttonStyle">@style/Widget.Mastodon.Button.Primary_DarkOnLight</item>
|
||||
<item name="secondaryButtonStyle">@style/Widget.Mastodon.Button.Secondary_DarkOnLight</item>
|
||||
|
@ -19,7 +20,7 @@
|
|||
<item name="colorBackgroundLight">@color/gray_50</item>
|
||||
<item name="colorBackgroundLightest">@color/gray_25</item>
|
||||
<item name="colorDarkIcon">@color/gray_900</item>
|
||||
<item name="android:windowBackground">@color/white</item>
|
||||
<item name="colorWindowBackground">@color/white</item>
|
||||
<item name="android:statusBarColor">@color/actionbar_bg</item>
|
||||
<item name="android:navigationBarColor">@color/navigation_bar_bg</item>
|
||||
<item name="android:actionBarTheme">@style/Theme.Mastodon.Toolbar</item>
|
||||
|
@ -37,6 +38,7 @@
|
|||
<item name="android:enforceStatusBarContrast" tools:ignore="NewApi">false</item>
|
||||
<item name="appkitBackDrawable">@drawable/ic_fluent_arrow_left_24_regular</item>
|
||||
<item name="android:splitMotionEvents">false</item>
|
||||
<item name="android:windowBackground">?colorWindowBackground</item>
|
||||
|
||||
<item name="android:buttonStyle">@style/Widget.Mastodon.Button.Primary_LightOnDark</item>
|
||||
<item name="secondaryButtonStyle">@style/Widget.Mastodon.Button.Secondary_LightOnDark</item>
|
||||
|
@ -50,7 +52,7 @@
|
|||
<item name="colorBackgroundLight">@color/gray_700</item>
|
||||
<item name="colorBackgroundLightest">@color/gray_700</item>
|
||||
<item name="colorDarkIcon">@color/gray_25</item>
|
||||
<item name="android:windowBackground">@color/gray_800</item>
|
||||
<item name="colorWindowBackground">@color/gray_800</item>
|
||||
<item name="android:statusBarColor">@color/actionbar_bg_dark</item>
|
||||
<item name="android:navigationBarColor">@color/actionbar_bg_dark</item>
|
||||
<item name="android:actionBarTheme">@style/Theme.Mastodon.Toolbar.Dark</item>
|
||||
|
|
Loading…
Reference in New Issue