animated previews

This commit is contained in:
Yuriy Liskov
2020-10-14 08:22:54 +03:00
parent 6489861dc7
commit 9e0b99381d
20 changed files with 663 additions and 94 deletions

View File

@@ -22,6 +22,7 @@ public final class Video implements Parcelable {
public String cardImageUrl;
public String studio;
public String badge;
public String previewUrl;
public int percentWatched;
public MediaItem mediaItem;
@@ -77,6 +78,7 @@ public final class Video implements Parcelable {
video.studio = item.getAuthor();
video.percentWatched = item.getPercentWatched();
video.badge = item.getBadgeText();
video.previewUrl = item.getVideoPreviewUrl();
video.mediaItem = item;
return video;

View File

@@ -152,6 +152,7 @@ public class StateUpdater extends PlayerEventListenerHelper {
public void onPlayEnd() {
Video video = mController.getVideo();
// In case we start to watch the video again
if (video != null) {
mStates.remove(video.videoId);
}

View File

@@ -103,6 +103,8 @@ dependencies {
implementation 'androidx.recyclerview:recyclerview:' + appCompatXLibraryVersion
implementation 'com.github.bumptech.glide:glide:' + glideVersion
annotationProcessor 'com.github.bumptech.glide:compiler:' + glideVersion
implementation 'com.zlc.glide:webpdecoder:2.0.' + glideVersion
implementation 'com.google.android.exoplayer:exoplayer:' + amazonExoplayerVersion
implementation 'com.google.android.exoplayer:extension-leanback:' + amazonExoplayerVersion

View File

@@ -88,6 +88,7 @@ public class CardPresenter extends Presenter {
cardView.setTitleText(video.title);
cardView.setContentText(video.description);
cardView.setBadgeText(video.badge);
cardView.setPreviewUrl(video.previewUrl);
if (video.cardImageUrl != null) {
// Set card size from dimension resources.

View File

@@ -3,32 +3,29 @@ package com.liskovsoft.smartyoutubetv2.tv.ui.widgets.textbadgecard;
import android.content.Context;
import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.leanback.widget.ImageCardView;
import com.liskovsoft.smartyoutubetv2.tv.R;
public class TextBadgeImageCardView extends ImageCardView {
private TextView mBadgeText;
private TextBadgeImageView mTextBadgeImageLayout;
public TextBadgeImageCardView(Context context) {
super(context);
createTextBadge();
init();
}
public TextBadgeImageCardView(Context context, AttributeSet attrs) {
super(context, attrs);
createTextBadge();
init();
}
public TextBadgeImageCardView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
createTextBadge();
init();
}
private void enableTextAnimation(boolean enable) {
@@ -53,31 +50,15 @@ public class TextBadgeImageCardView extends ImageCardView {
}
}
private void createTextBadge() {
ViewGroup wrapper = findViewById(R.id.main_image_wrapper);
if (wrapper != null) {
LayoutInflater inflater = LayoutInflater.from(getContext());
int layoutId = R.layout.image_card_view_badge;
mBadgeText = (TextView) inflater.inflate(layoutId, wrapper, false);
wrapper.addView(mBadgeText);
}
private void init() {
mTextBadgeImageLayout = findViewById(R.id.main_image_wrapper);
}
/**
* Sets the badge text.
*/
public void setBadgeText(String text) {
if (mBadgeText == null) {
return;
}
mBadgeText.setText(text);
if (text != null) {
mBadgeText.setVisibility(View.VISIBLE);
} else {
mBadgeText.setVisibility(View.GONE);
}
mTextBadgeImageLayout.setBadgeText(text);
}
@Override
@@ -85,5 +66,18 @@ public class TextBadgeImageCardView extends ImageCardView {
super.setSelected(selected);
enableTextAnimation(selected);
enableVideoPreview(selected);
}
private void enableVideoPreview(boolean selected) {
if (selected) {
mTextBadgeImageLayout.setLoading();
} else {
mTextBadgeImageLayout.setFinished();
}
}
public void setPreviewUrl(String previewUrl) {
mTextBadgeImageLayout.setPreviewUrl(previewUrl);
}
}

View File

@@ -1,43 +0,0 @@
package com.liskovsoft.smartyoutubetv2.tv.ui.widgets.textbadgecard;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import com.liskovsoft.smartyoutubetv2.tv.R;
public class TextBadgeImageLayout extends RelativeLayout {
private ImageView mMainImage;
public TextBadgeImageLayout(Context context) {
super(context);
init();
}
public TextBadgeImageLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public TextBadgeImageLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
inflate(getContext(), R.layout.image_card_view, this);
mMainImage = findViewById(R.id.main_image);
}
/**
* Main trick is to apply visibility to child image views<br/>
* See: androidx.leanback.widget.BaseCardView#findChildrenViews()
*/
@Override
public void setVisibility(int visibility) {
super.setVisibility(visibility);
if (mMainImage != null) {
mMainImage.setVisibility(visibility);
}
}
}

View File

@@ -0,0 +1,117 @@
package com.liskovsoft.smartyoutubetv2.tv.ui.widgets.textbadgecard;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
import com.liskovsoft.smartyoutubetv2.tv.R;
public class TextBadgeImageView extends RelativeLayout {
private ImageView mMainImage;
private ImageView mPreviewImage;
private TextView mBadgeText;
private String mPreviewUrl;
public TextBadgeImageView(Context context) {
super(context);
init();
}
public TextBadgeImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public TextBadgeImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
inflate(getContext(), R.layout.text_badge_image_view, this);
mMainImage = findViewById(R.id.main_image);
mPreviewImage = findViewById(R.id.preview_image);
mBadgeText = findViewById(R.id.extra_text_badge);
}
/**
* Main trick is to apply visibility to child image views<br/>
* See: androidx.leanback.widget.BaseCardView#findChildrenViews()
*/
@Override
public void setVisibility(int visibility) {
super.setVisibility(visibility);
if (mMainImage != null) {
mMainImage.setVisibility(visibility);
}
}
/**
* Sets the badge text.
*/
public void setBadgeText(String text) {
if (mBadgeText == null) {
return;
}
mBadgeText.setText(text);
if (text != null) {
mBadgeText.setVisibility(View.VISIBLE);
} else {
mBadgeText.setVisibility(View.GONE);
}
}
public void setPreviewUrl(String videoUrl) {
mPreviewUrl = videoUrl;
}
//public ImageView getImageView() {
// return mImageView;
//}
public void setLoading() {
if (mPreviewUrl == null) {
return;
}
mPreviewImage.setVisibility(View.VISIBLE);
mMainImage.setVisibility(View.GONE);
Glide.with(getContext())
.load(mPreviewUrl)
.listener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource,
boolean isFirstResource) {
//mMainImage.setVisibility(View.GONE);
//mPreviewImage.setVisibility(View.VISIBLE);
return false;
}
})
.into(mPreviewImage);
}
public void setFinished() {
if (mPreviewUrl == null) {
return;
}
mPreviewImage.setVisibility(View.GONE);
mPreviewImage.setImageDrawable(null);
mMainImage.setVisibility(View.VISIBLE);
}
}

View File

@@ -0,0 +1,58 @@
package com.liskovsoft.smartyoutubetv2.tv.ui.widgets.videocard;
import android.content.Context;
import android.media.MediaPlayer;
import android.net.Uri;
import android.util.AttributeSet;
import android.widget.VideoView;
public class LoopingVideoView extends VideoView {
private MediaPlayer mMediaPlayer;
public LoopingVideoView(Context context) {
super(context);
}
public LoopingVideoView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public LoopingVideoView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public LoopingVideoView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public void setupMediaPlayer(String url, final OnVideoReadyListener onVideoReadyListener) {
setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mMediaPlayer = mp;
mMediaPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
@Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
if (percent > 20) onVideoReadyListener.onVideoReady();
}
});
mMediaPlayer.setLooping(true);
mMediaPlayer.setVolume(0, 0);
mMediaPlayer.start();
}
});
setVideoURI(Uri.parse(url));
}
public void stopMediaPlayer() {
if (mMediaPlayer != null) {
mMediaPlayer.release();
}
}
public interface OnVideoReadyListener {
void onVideoReady();
}
}

View File

@@ -0,0 +1,79 @@
package com.liskovsoft.smartyoutubetv2.tv.ui.widgets.videocard;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ProgressBar;
import com.liskovsoft.smartyoutubetv2.tv.R;
public class PreviewCardView extends FrameLayout {
FrameLayout mMainContainer;
LoopingVideoView mVideoView;
ImageView mImageView;
View mOverlayView;
ProgressBar mProgressCard;
private String mVideoUrl;
public PreviewCardView(Context context) {
super(context);
init();
}
public PreviewCardView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public PreviewCardView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
View view = inflate(getContext(), R.layout.widget_preview_card, this);
mMainContainer = view.findViewById(R.id.main_container);
mVideoView = view.findViewById(R.id.main_video);
mImageView = view.findViewById(R.id.main_image);
mOverlayView = view.findViewById(R.id.view_overlay);
mProgressCard = view.findViewById(R.id.progress_card);
}
public void setVideoUrl(String videoUrl) {
mVideoUrl = videoUrl;
}
public ImageView getImageView() {
return mImageView;
}
public void setLoading() {
mOverlayView.setVisibility(View.VISIBLE);
mProgressCard.setVisibility(View.VISIBLE);
mVideoView.setVisibility(View.VISIBLE);
mVideoView.setupMediaPlayer(mVideoUrl, new LoopingVideoView.OnVideoReadyListener() {
@Override
public void onVideoReady() {
mOverlayView.setVisibility(View.INVISIBLE);
mProgressCard.setVisibility(View.INVISIBLE);
mImageView.setVisibility(View.INVISIBLE);
}
});
}
public void setFinished() {
mVideoView.setVisibility(View.INVISIBLE);
mVideoView.stopMediaPlayer();
mImageView.setVisibility(View.VISIBLE);
mOverlayView.setVisibility(View.INVISIBLE);
mProgressCard.setVisibility(View.INVISIBLE);
}
}

View File

@@ -0,0 +1,217 @@
package com.liskovsoft.smartyoutubetv2.tv.ui.widgets.videocard;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.leanback.widget.BaseCardView;
import com.liskovsoft.smartyoutubetv2.tv.R;
import com.liskovsoft.smartyoutubetv2.tv.util.NetworkUtil;
public class VideoCardView extends BaseCardView {
public static final int CARD_TYPE_FLAG_IMAGE_ONLY = 0;
public static final int CARD_TYPE_FLAG_TITLE = 1;
public static final int CARD_TYPE_FLAG_CONTENT = 2;
PreviewCardView mPreviewCard;
ViewGroup mInfoArea;
private TextView mTitleView;
private TextView mContentView;
private boolean mAttachedToWindow;
public VideoCardView(Context context, int styleResId) {
super(new ContextThemeWrapper(context, styleResId), null, 0);
buildImageCardView(styleResId);
}
public VideoCardView(Context context, AttributeSet attrs, int defStyleAttr) {
super(getStyledContext(context, attrs, defStyleAttr), attrs, defStyleAttr);
buildImageCardView(getImageCardViewStyle(context, attrs, defStyleAttr));
}
@Override
public boolean hasOverlappingRendering() {
return false;
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mAttachedToWindow = true;
ImageView mImageView = mPreviewCard.getImageView();
if (mImageView.getAlpha() == 0) fadeIn();
}
@Override
protected void onDetachedFromWindow() {
ImageView mImageView = mPreviewCard.getImageView();
mAttachedToWindow = false;
mImageView.animate().cancel();
mImageView.setAlpha(1f);
super.onDetachedFromWindow();
}
private void buildImageCardView(int styleResId) {
// Make sure the ImageCardView is focusable.
setFocusable(true);
setFocusableInTouchMode(true);
LayoutInflater inflater = LayoutInflater.from(getContext());
View view = inflater.inflate(R.layout.lb_video_card_view, this);
mPreviewCard = view.findViewById(R.id.layout_preview_card);
mInfoArea = view.findViewById(R.id.info_field);
TypedArray cardAttrs =
getContext().obtainStyledAttributes(styleResId, R.styleable.lbImageCardView);
int cardType =
cardAttrs.getInt(
R.styleable.lbImageCardView_lbImageCardViewType, CARD_TYPE_FLAG_IMAGE_ONLY);
boolean hasImageOnly = cardType == CARD_TYPE_FLAG_IMAGE_ONLY;
boolean hasTitle = (cardType & CARD_TYPE_FLAG_TITLE) == CARD_TYPE_FLAG_TITLE;
boolean hasContent = (cardType & CARD_TYPE_FLAG_CONTENT) == CARD_TYPE_FLAG_CONTENT;
if (hasImageOnly) {
removeView(mInfoArea);
cardAttrs.recycle();
return;
}
// Create children
if (hasTitle) {
mTitleView = (TextView) inflater.inflate(R.layout.lb_image_card_view_themed_title, mInfoArea, false);
mInfoArea.addView(mTitleView);
}
if (hasContent) {
mContentView = (TextView) inflater.inflate(R.layout.lb_image_card_view_themed_content, mInfoArea, false);
mInfoArea.addView(mContentView);
}
// Backward compatibility: Newly created ImageCardViews should change
// the InfoArea's background color in XML using the corresponding style.
// However, since older implementations might make use of the
// 'infoAreaBackground' attribute, we have to make sure to support it.
// If the user has set a specific value here, it will differ from null.
// In this case, we do want to override the value set in the style.
Drawable background = cardAttrs.getDrawable(R.styleable.lbImageCardView_infoAreaBackground);
if (null != background) {
setInfoAreaBackground(background);
}
cardAttrs.recycle();
}
private static Context getStyledContext(Context context, AttributeSet attrs, int defStyleAttr) {
int style = getImageCardViewStyle(context, attrs, defStyleAttr);
return new ContextThemeWrapper(context, style);
}
private static int getImageCardViewStyle(Context context, AttributeSet attrs, int defStyleAttr) {
// Read style attribute defined in XML layout.
int style = null == attrs ? 0 : attrs.getStyleAttribute();
if (0 == style) {
// Not found? Read global ImageCardView style from Theme attribute.
TypedArray styledAttrs = context.obtainStyledAttributes(R.styleable.LeanbackTheme);
style = styledAttrs.getResourceId(R.styleable.LeanbackTheme_imageCardViewStyle, 0);
styledAttrs.recycle();
}
return style;
}
public VideoCardView(Context context) {
this(context, null);
}
public VideoCardView(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.imageCardViewStyle);
}
/**
* Returns the main image view.
*/
public final ImageView getMainImageView() {
return mPreviewCard.getImageView();
}
/**
* Sets the layout dimensions of the ImageView.
*/
public void setMainContainerDimensions(int width, int height) {
ViewGroup.LayoutParams lp = mPreviewCard.getLayoutParams();
lp.width = width;
lp.height = height;
mPreviewCard.setLayoutParams(lp);
}
/**
* Sets the info area background drawable.
*/
public void setInfoAreaBackground(Drawable drawable) {
if (mInfoArea != null) {
mInfoArea.setBackground(drawable);
}
}
public void setVideoUrl(String url) {
mPreviewCard.setVideoUrl(url);
}
public void startVideo() {
if (NetworkUtil.isNetworkConnected(getContext())) {
mPreviewCard.setLoading();
}
}
public void stopVideo() {
mPreviewCard.setFinished();
}
/**
* Sets the title text.
*/
public void setTitleText(CharSequence text) {
if (mTitleView == null) {
return;
}
mTitleView.setText(text);
}
/**
* Sets the content text.
*/
public void setContentText(CharSequence text) {
if (mContentView == null) {
return;
}
mContentView.setText(text);
}
private void fadeIn() {
ImageView mImageView = mPreviewCard.getImageView();
mImageView.setAlpha(0f);
if (mAttachedToWindow) {
int duration =
mImageView.getResources().getInteger(android.R.integer.config_shortAnimTime);
mImageView.animate().alpha(1f).setDuration(duration);
}
}
@Override
public void setSelected(boolean selected) {
super.setSelected(selected);
if (selected) {
startVideo();
} else {
stopVideo();
}
}
}

View File

@@ -0,0 +1,16 @@
package com.liskovsoft.smartyoutubetv2.tv.util;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
public class NetworkUtil {
public static boolean isNetworkConnected(Context context) {
ConnectivityManager cm =
(ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
return activeNetwork != null &&
activeNetwork.isConnectedOrConnecting();
}
}

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_image"
style="?attr/imageCardViewImageStyle"/>

View File

@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:visibility="gone"
android:id="@+id/extra_text_badge"
android:layout_alignBottom="@+id/main_image"
android:layout_alignEnd="@+id/main_image"
android:layout_marginEnd="@dimen/lb_basic_card_info_badge_margin"
android:layout_marginBottom="@dimen/lb_basic_card_info_badge_margin"
android:background="@color/black"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
android:includeFontPadding="false"
android:paddingStart="@dimen/lb_details_description_title_padding_adjust_bottom"
android:paddingEnd="@dimen/lb_details_description_title_padding_adjust_bottom"
style="@style/TextAppearance.Leanback.ImageCardView.Content" />

View File

@@ -4,11 +4,11 @@
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:lb="http://schemas.android.com/apk/res-auto" >
<com.liskovsoft.smartyoutubetv2.tv.ui.widgets.textbadgecard.TextBadgeImageLayout
<com.liskovsoft.smartyoutubetv2.tv.ui.widgets.textbadgecard.TextBadgeImageView
android:id="@+id/main_image_wrapper"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.liskovsoft.smartyoutubetv2.tv.ui.widgets.textbadgecard.TextBadgeImageLayout>
</com.liskovsoft.smartyoutubetv2.tv.ui.widgets.textbadgecard.TextBadgeImageView>
<androidx.leanback.widget.NonOverlappingRelativeLayout
android:id="@+id/info_field"

View File

@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:lb="http://schemas.android.com/apk/res-auto">
<com.liskovsoft.smartyoutubetv2.tv.ui.widgets.videocard.PreviewCardView
android:id="@+id/layout_preview_card"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
lb:layout_viewType="main" />
<androidx.leanback.widget.NonOverlappingFrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
lb:layout_viewType="info">
<RelativeLayout
android:id="@+id/info_field"
android:layout_width="match_parent"
android:layout_height="@dimen/lb_basic_card_info_height"
android:layout_centerHorizontal="true"
android:padding="@dimen/lb_basic_card_info_padding">
<TextView
android:id="@+id/title_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_marginLeft="@dimen/lb_basic_card_info_text_margin"
android:layout_marginTop="@dimen/lb_basic_card_info_text_margin"
android:ellipsize="end"
android:fontFamily="sans-serif-condensed"
android:maxLines="1"
android:textColor="@color/lb_basic_card_title_text_color"
android:textSize="@dimen/lb_basic_card_title_text_size" />
<TextView
android:id="@+id/content_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_marginBottom="@dimen/lb_basic_card_info_text_margin"
android:layout_marginLeft="@dimen/lb_basic_card_info_text_margin"
android:ellipsize="none"
android:fontFamily="sans-serif-condensed"
android:maxLines="1"
android:textColor="@color/lb_basic_card_content_text_color"
android:textSize="@dimen/lb_basic_card_content_text_size" />
<ImageView
android:id="@+id/extra_badge"
android:layout_width="@dimen/lb_basic_card_info_badge_size"
android:layout_height="@dimen/lb_basic_card_info_badge_size"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:contentDescription="@null"
android:scaleType="fitCenter"
android:visibility="gone" />
<ImageView
android:id="@+id/fade_mask"
android:layout_width="wrap_content"
android:layout_height="@dimen/lb_basic_card_info_badge_size"
android:layout_alignParentBottom="true"
android:layout_toStartOf="@id/extra_badge"
android:contentDescription="@null"
android:scaleType="fitCenter"
android:visibility="gone" />
</RelativeLayout>
</androidx.leanback.widget.NonOverlappingFrameLayout>
</merge>

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView
android:id="@+id/main_image"
style="?attr/imageCardViewImageStyle"/>
<ImageView
android:visibility="gone"
android:id="@+id/preview_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:adjustViewBounds="true"
android:layout_alignTop="@+id/main_image"
android:layout_alignStart="@+id/main_image"
/>
<TextView android:visibility="gone"
android:id="@+id/extra_text_badge"
android:layout_alignBottom="@+id/main_image"
android:layout_alignEnd="@+id/main_image"
android:layout_marginEnd="@dimen/lb_basic_card_info_badge_margin"
android:layout_marginBottom="@dimen/lb_basic_card_info_badge_margin"
android:background="@color/black"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
android:includeFontPadding="false"
android:paddingStart="@dimen/lb_details_description_title_padding_adjust_bottom"
android:paddingEnd="@dimen/lb_details_description_title_padding_adjust_bottom"
style="@style/TextAppearance.Leanback.ImageCardView.Content" />
</merge>

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.liskovsoft.smartyoutubetv2.tv.ui.widgets.videocard.LoopingVideoView
android:id="@+id/main_video"
android:layout_width="175dp"
android:layout_height="175dp"
android:visibility="invisible" />
<ImageView
android:id="@+id/main_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@null"
android:adjustViewBounds="true"
android:scaleType="centerCrop" />
<View
android:id="@+id/view_overlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black_87pc"
android:visibility="invisible" />
<ProgressBar
android:id="@+id/progress_card"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="invisible" />
</FrameLayout>

View File

@@ -19,4 +19,5 @@
<color name="icon_background">#4A4F51</color>
<color name="icon_alt_background">#2A2F51</color>
<color name="player_background">#FF000000</color>
<color name="black_87pc">#77000000</color>
</resources>

View File

@@ -5,6 +5,15 @@
<dimen name="card_width">205dp</dimen>
<dimen name="card_height">115dp</dimen>
<dimen name="lb_basic_card_main_width">140dp</dimen>
<dimen name="lb_basic_card_main_height">188dp</dimen>
<dimen name="lb_basic_card_info_height">52dp</dimen>
<dimen name="lb_basic_card_info_padding">6dp</dimen>
<dimen name="lb_basic_card_info_text_margin">2dp</dimen>
<dimen name="lb_basic_card_title_text_size">16sp</dimen>
<dimen name="lb_basic_card_content_text_size">12sp</dimen>
<dimen name="lb_basic_card_info_badge_size">16dp</dimen>
<!-- Elements below aren't used in the app -->
<dimen name="grid_item_width">100dp</dimen>