/* * mygram-droid: Android TV client for Foldergram. * Copyright (C) 2026 Danilo M. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ package mygram.droid; import android.content.Context; import android.graphics.Color; import android.graphics.drawable.GradientDrawable; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; import java.util.List; /** Thumbnail tiles for rows and grids: posts, folders and the Continue tile. */ final class TileAdapter extends RecyclerView.Adapter { static final class Tile { final String image, label; final int icon, postId; final Runnable click; /** Photo or video mark in the top left; 0 for none. */ int badge; /** image or icon is shown; postId is -1 for tiles that are not posts. */ Tile(String image, String label, int icon, int postId, Runnable click) { this.image = image; this.label = label; this.icon = icon; this.postId = postId; this.click = click; } } static Tile post(Post p, Runnable click) { Tile t = new Tile(p.media.get(0).thumbnailUrl, null, 0, p.id, click); t.badge = p.media.get(0).video ? R.drawable.ic_videocam : R.drawable.ic_photo; return t; } static final class Holder extends RecyclerView.ViewHolder { final ImageView image, heart, badge; final TextView label; Holder(View v, ImageView image, TextView label, ImageView heart, ImageView badge) { super(v); this.image = image; this.label = label; this.heart = heart; this.badge = badge; } } private final List tiles; private final int widthDp, heightDp; TileAdapter(List tiles, int widthDp, int heightDp) { this.tiles = tiles; this.widthDp = widthDp; this.heightDp = heightDp; } @Override public Holder onCreateViewHolder(ViewGroup parent, int type) { Context c = parent.getContext(); FrameLayout frame = new FrameLayout(c); RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(Ui.dp(c, widthDp), Ui.dp(c, heightDp)); int m = Ui.dp(c, 12); lp.setMargins(m, m, m, m); frame.setLayoutParams(lp); frame.setBackgroundColor(0xFF222222); ImageView image = new ImageView(c); frame.addView(image, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); TextView label = Ui.text(c, "", 14); label.setShadowLayer(6, 0, 0, Color.BLACK); int p = Ui.dp(c, 8); label.setPadding(p, p, p, p); frame.addView(label, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.BOTTOM)); ImageView heart = new ImageView(c); heart.setImageResource(R.drawable.ic_favorite); heart.setColorFilter(Ui.RED); heart.setContentDescription("Liked"); int s = Ui.dp(c, 22); FrameLayout.LayoutParams hp = new FrameLayout.LayoutParams(s, s, Gravity.TOP | Gravity.END); hp.setMargins(p, p, p, p); frame.addView(heart, hp); ImageView badge = new ImageView(c); GradientDrawable dot = new GradientDrawable(); dot.setShape(GradientDrawable.OVAL); dot.setColor(0x80000000); // readable on bright thumbnails badge.setBackground(dot); int bp = Ui.dp(c, 4); badge.setPadding(bp, bp, bp, bp); int bs = Ui.dp(c, 26); FrameLayout.LayoutParams bl = new FrameLayout.LayoutParams(bs, bs, Gravity.TOP | Gravity.START); bl.setMargins(p, p, p, p); frame.addView(badge, bl); Ui.focusable(frame); return new Holder(frame, image, label, heart, badge); } @Override public void onBindViewHolder(Holder h, int position) { Tile t = tiles.get(position); h.itemView.setScaleX(1f); // a recycled tile may still carry the focus zoom h.itemView.setScaleY(1f); if (t.image != null) { h.image.setScaleType(ImageView.ScaleType.CENTER_CROP); Glide.with(h.image).load(t.image).into(h.image); } else { Glide.with(h.image).clear(h.image); h.image.setScaleType(ImageView.ScaleType.CENTER); h.image.setImageResource(t.icon); } h.label.setText(t.label); h.label.setVisibility(t.label == null ? View.GONE : View.VISIBLE); h.badge.setVisibility(t.badge == 0 ? View.GONE : View.VISIBLE); h.badge.setImageResource(t.badge); h.badge.setContentDescription(t.badge == R.drawable.ic_videocam ? "Video" : "Photo"); h.heart.setVisibility(t.postId >= 0 && Likes.has(t.postId) ? View.VISIBLE : View.GONE); h.itemView.setContentDescription(t.label != null ? t.label : "Post"); h.itemView.setOnClickListener(v -> t.click.run()); } @Override public int getItemCount() { return tiles.size(); } }