Improve link preview cards (#1330)
* improve card frame * add placeholder for empty image * improve layout, Pleroma compatibility, show author name as description fallback * reset okhttp logging level * remove unneeded statement
This commit is contained in:
parent
e6d91c1cf3
commit
b825f42c7a
13 changed files with 69 additions and 31 deletions
|
@ -154,6 +154,7 @@ dependencies {
|
||||||
//Glide
|
//Glide
|
||||||
implementation 'com.github.bumptech.glide:glide:4.9.0'
|
implementation 'com.github.bumptech.glide:glide:4.9.0'
|
||||||
implementation 'com.github.bumptech.glide:okhttp3-integration:4.9.0'
|
implementation 'com.github.bumptech.glide:okhttp3-integration:4.9.0'
|
||||||
|
implementation 'jp.wasabeef:glide-transformations:4.0.1'
|
||||||
|
|
||||||
//Add some useful extensions
|
//Add some useful extensions
|
||||||
implementation 'androidx.core:core-ktx:1.2.0-alpha01'
|
implementation 'androidx.core:core-ktx:1.2.0-alpha01'
|
||||||
|
|
|
@ -17,6 +17,7 @@ import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.bumptech.glide.Glide;
|
import com.bumptech.glide.Glide;
|
||||||
|
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
|
||||||
import com.keylesspalace.tusky.R;
|
import com.keylesspalace.tusky.R;
|
||||||
import com.keylesspalace.tusky.entity.Card;
|
import com.keylesspalace.tusky.entity.Card;
|
||||||
import com.keylesspalace.tusky.entity.Status;
|
import com.keylesspalace.tusky.entity.Status;
|
||||||
|
@ -31,6 +32,8 @@ import java.util.Date;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import jp.wasabeef.glide.transformations.RoundedCornersTransformation;
|
||||||
|
|
||||||
class StatusDetailedViewHolder extends StatusBaseViewHolder {
|
class StatusDetailedViewHolder extends StatusBaseViewHolder {
|
||||||
private TextView reblogs;
|
private TextView reblogs;
|
||||||
private TextView favourites;
|
private TextView favourites;
|
||||||
|
@ -152,20 +155,32 @@ class StatusDetailedViewHolder extends StatusBaseViewHolder {
|
||||||
final Card card = status.getCard();
|
final Card card = status.getCard();
|
||||||
cardView.setVisibility(View.VISIBLE);
|
cardView.setVisibility(View.VISIBLE);
|
||||||
cardTitle.setText(card.getTitle());
|
cardTitle.setText(card.getTitle());
|
||||||
|
if(TextUtils.isEmpty(card.getDescription()) && TextUtils.isEmpty(card.getAuthorName())) {
|
||||||
|
cardDescription.setVisibility(View.GONE);
|
||||||
|
} else {
|
||||||
|
cardDescription.setVisibility(View.VISIBLE);
|
||||||
|
if(TextUtils.isEmpty(card.getDescription())) {
|
||||||
|
cardDescription.setText(card.getAuthorName());
|
||||||
|
} else {
|
||||||
cardDescription.setText(card.getDescription());
|
cardDescription.setText(card.getDescription());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cardUrl.setText(card.getUrl());
|
cardUrl.setText(card.getUrl());
|
||||||
|
|
||||||
if (card.getWidth() > 0 && card.getHeight() > 0 && !TextUtils.isEmpty(card.getImage())) {
|
if (!TextUtils.isEmpty(card.getImage())) {
|
||||||
cardImage.setVisibility(View.VISIBLE);
|
|
||||||
|
RoundedCornersTransformation.CornerType cornertype;
|
||||||
|
|
||||||
if (card.getWidth() > card.getHeight()) {
|
if (card.getWidth() > card.getHeight()) {
|
||||||
cardView.setOrientation(LinearLayout.VERTICAL);
|
cardView.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
|
||||||
cardImage.getLayoutParams().height = cardImage.getContext().getResources()
|
cardImage.getLayoutParams().height = cardImage.getContext().getResources()
|
||||||
.getDimensionPixelSize(R.dimen.card_image_vertical_height);
|
.getDimensionPixelSize(R.dimen.card_image_vertical_height);
|
||||||
cardImage.getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT;
|
cardImage.getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||||
cardInfo.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
|
cardInfo.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||||
cardInfo.getLayoutParams().width = ViewGroup.LayoutParams.WRAP_CONTENT;
|
cardInfo.getLayoutParams().width = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||||
|
cornertype = RoundedCornersTransformation.CornerType.TOP;
|
||||||
} else {
|
} else {
|
||||||
cardView.setOrientation(LinearLayout.HORIZONTAL);
|
cardView.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
cardImage.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
|
cardImage.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||||
|
@ -173,17 +188,28 @@ class StatusDetailedViewHolder extends StatusBaseViewHolder {
|
||||||
.getDimensionPixelSize(R.dimen.card_image_horizontal_width);
|
.getDimensionPixelSize(R.dimen.card_image_horizontal_width);
|
||||||
cardInfo.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
|
cardInfo.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||||
cardInfo.getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT;
|
cardInfo.getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||||
|
cornertype = RoundedCornersTransformation.CornerType.LEFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
cardView.setClipToOutline(true);
|
int radius = cardImage.getContext().getResources()
|
||||||
|
.getDimensionPixelSize(R.dimen.card_radius);
|
||||||
|
|
||||||
|
cardView.setClipToOutline(true);
|
||||||
Glide.with(cardImage)
|
Glide.with(cardImage)
|
||||||
.load(card.getImage())
|
.load(card.getImage())
|
||||||
.centerCrop()
|
.transform(new CenterCrop(), new RoundedCornersTransformation(radius, 0, cornertype))
|
||||||
.into(cardImage);
|
.into(cardImage);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
cardImage.setVisibility(View.GONE);
|
cardView.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
|
cardImage.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||||
|
cardImage.getLayoutParams().width = cardImage.getContext().getResources()
|
||||||
|
.getDimensionPixelSize(R.dimen.card_image_horizontal_width);
|
||||||
|
cardInfo.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||||
|
cardInfo.getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||||
|
|
||||||
|
cardImage.setImageResource(R.drawable.card_image_placeholder);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cardView.setOnClickListener(v -> LinkHelper.openLink(card.getUrl(), v.getContext()));
|
cardView.setOnClickListener(v -> LinkHelper.openLink(card.getUrl(), v.getContext()));
|
||||||
|
|
|
@ -16,13 +16,17 @@
|
||||||
package com.keylesspalace.tusky.entity
|
package com.keylesspalace.tusky.entity
|
||||||
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import android.text.Spanned
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.android.parcel.Parcelize
|
||||||
|
import kotlinx.android.parcel.WriteWith
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class Card(
|
data class Card(
|
||||||
val url: String,
|
val url: String,
|
||||||
val title: String,
|
val title: @WriteWith<SpannedParceler>() Spanned,
|
||||||
val description: String,
|
val description: @WriteWith<SpannedParceler>() Spanned,
|
||||||
|
@SerializedName("author_name") val authorName: String,
|
||||||
val image: String,
|
val image: String,
|
||||||
val type: String,
|
val type: String,
|
||||||
val width: Int,
|
val width: Int,
|
||||||
|
|
|
@ -130,7 +130,7 @@ data class Status(
|
||||||
|
|
||||||
data class Application (
|
data class Application (
|
||||||
val name: String,
|
val name: String,
|
||||||
val website: String
|
val website: String?
|
||||||
)
|
)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
5
app/src/main/res/drawable/card_frame.xml
Normal file
5
app/src/main/res/drawable/card_frame.xml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<corners android:radius="6dp" />
|
||||||
|
<stroke android:color="?attr/card_background_color" android:width="1dp" />
|
||||||
|
</shape>
|
|
@ -1,6 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<corners android:radius="5dp" />
|
|
||||||
<stroke android:color="@color/text_color_tertiary_dark" android:width="1px" />
|
|
||||||
<padding android:bottom="1px" android:top="1px" android:left="1px" android:right="1px"/>
|
|
||||||
</shape>
|
|
|
@ -1,6 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<corners android:radius="5dp" />
|
|
||||||
<stroke android:color="@color/text_color_tertiary_light" android:width="1px" />
|
|
||||||
<padding android:bottom="1px" android:top="1px" android:left="1px" android:right="1px"/>
|
|
||||||
</shape>
|
|
10
app/src/main/res/drawable/card_image_placeholder.xml
Normal file
10
app/src/main/res/drawable/card_image_placeholder.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="48dp"
|
||||||
|
android:height="48dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="?android:attr/textColorTertiary"
|
||||||
|
android:pathData="M6,2A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2H6M6,4H13V9H18V20H6V4M8,12V14H16V12H8M8,16V18H13V16H8Z" />
|
||||||
|
</vector>
|
|
@ -134,8 +134,10 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:background="?attr/card_background"
|
android:background="@drawable/card_frame"
|
||||||
android:clipChildren="true"
|
android:clipChildren="true"
|
||||||
|
android:foreground="?attr/selectableItemBackground"
|
||||||
|
android:minHeight="80dp"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/status_content"
|
app:layout_constraintTop_toBottomOf="@+id/status_content"
|
||||||
tools:visibility="gone">
|
tools:visibility="gone">
|
||||||
|
@ -144,7 +146,10 @@
|
||||||
android:id="@+id/card_image"
|
android:id="@+id/card_image"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="300dp"
|
android:layout_height="300dp"
|
||||||
android:background="?attr/card_image_background" />
|
android:layout_margin="1dp"
|
||||||
|
android:background="?attr/card_background_color"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:scaleType="center" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/card_info"
|
android:id="@+id/card_info"
|
||||||
|
@ -164,7 +169,7 @@
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:fontFamily="sans-serif-medium"
|
android:fontFamily="sans-serif-medium"
|
||||||
android:lines="1"
|
android:lines="1"
|
||||||
android:textColor="?android:textColorPrimary"
|
android:textColor="?android:textColorSecondary"
|
||||||
android:textSize="?attr/status_text_medium" />
|
android:textSize="?attr/status_text_medium" />
|
||||||
|
|
||||||
<androidx.emoji.widget.EmojiTextView
|
<androidx.emoji.widget.EmojiTextView
|
||||||
|
|
|
@ -65,8 +65,7 @@
|
||||||
<item name="material_drawer_header_selection_text">@color/text_color_primary_dark</item>
|
<item name="material_drawer_header_selection_text">@color/text_color_primary_dark</item>
|
||||||
<item name="material_drawer_header_selection_subtext">@color/text_color_secondary_dark</item>
|
<item name="material_drawer_header_selection_subtext">@color/text_color_secondary_dark</item>
|
||||||
|
|
||||||
<item name="card_background">@drawable/card_frame_dark</item>
|
<item name="card_background_color">@color/color_primary_dark</item>
|
||||||
<item name="card_image_background">@color/text_color_tertiary_dark</item>
|
|
||||||
|
|
||||||
<item name="play_indicator_drawable">@drawable/ic_play_indicator_dark</item>
|
<item name="play_indicator_drawable">@drawable/ic_play_indicator_dark</item>
|
||||||
|
|
||||||
|
|
|
@ -35,8 +35,7 @@
|
||||||
<attr name="compose_content_warning_bar_background" format="reference" />
|
<attr name="compose_content_warning_bar_background" format="reference" />
|
||||||
<attr name="compose_reply_content_background" format="reference|color" />
|
<attr name="compose_reply_content_background" format="reference|color" />
|
||||||
<attr name="report_status_background_color" format="reference|color" />
|
<attr name="report_status_background_color" format="reference|color" />
|
||||||
<attr name="card_background" format="reference|color" />
|
<attr name="card_background_color" format="reference|color" />
|
||||||
<attr name="card_image_background" format="reference|color" />
|
|
||||||
<attr name="compound_button_color" format="reference" />
|
<attr name="compound_button_color" format="reference" />
|
||||||
<attr name="autocomplete_divider_drawable" format="reference" />
|
<attr name="autocomplete_divider_drawable" format="reference" />
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
<dimen name="text_content_margin">16dp</dimen>
|
<dimen name="text_content_margin">16dp</dimen>
|
||||||
<dimen name="status_sensitive_media_button_padding">5dp</dimen>
|
<dimen name="status_sensitive_media_button_padding">5dp</dimen>
|
||||||
|
|
||||||
<dimen name="card_image_vertical_height">160dp</dimen>
|
<dimen name="card_image_vertical_height">210dp</dimen>
|
||||||
<dimen name="card_image_horizontal_width">100dp</dimen>
|
<dimen name="card_image_horizontal_width">100dp</dimen>
|
||||||
|
|
||||||
<dimen name="compose_activity_snackbar_elevation">16dp</dimen>
|
<dimen name="compose_activity_snackbar_elevation">16dp</dimen>
|
||||||
|
@ -40,4 +40,6 @@
|
||||||
<dimen name="avatar_radius_36dp">4.5dp</dimen> <!-- 1/8 of 36dp -->
|
<dimen name="avatar_radius_36dp">4.5dp</dimen> <!-- 1/8 of 36dp -->
|
||||||
<dimen name="avatar_radius_24dp">3dp</dimen> <!-- 1/8 of 24dp -->
|
<dimen name="avatar_radius_24dp">3dp</dimen> <!-- 1/8 of 24dp -->
|
||||||
<dimen name="min_report_button_width">160dp</dimen>
|
<dimen name="min_report_button_width">160dp</dimen>
|
||||||
|
|
||||||
|
<dimen name="card_radius">5dp</dimen>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -125,8 +125,7 @@
|
||||||
<item name="material_drawer_header_selection_subtext">@color/text_color_secondary_dark
|
<item name="material_drawer_header_selection_subtext">@color/text_color_secondary_dark
|
||||||
</item> <!--Intentionally dark so it can be overlayed over the account's header image.-->
|
</item> <!--Intentionally dark so it can be overlayed over the account's header image.-->
|
||||||
|
|
||||||
<item name="card_background">@drawable/card_frame_light</item>
|
<item name="card_background_color">@color/color_primary_light</item>
|
||||||
<item name="card_image_background">@color/text_color_tertiary_light</item>
|
|
||||||
|
|
||||||
<item name="play_indicator_drawable">@drawable/ic_play_indicator_light</item>
|
<item name="play_indicator_drawable">@drawable/ic_play_indicator_light</item>
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue