/* * 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.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; /** 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) { return new Tile(p.media.get(0).thumbnailUrl, null, 0, p.id, click); } static final class Holder extends RecyclerView.ViewHolder { final ImageView image, heart; final TextView label; Holder(View v, ImageView image, TextView label, ImageView heart) { super(v); this.image = image; this.label = label; this.heart = heart; } } 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); Ui.focusable(frame); return new Holder(frame, image, label, heart); } @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.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(); } }