aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main/java/mygram/droid/TileAdapter.java
blob: 5e531098add80d42adf26e911fb4eade5ea329b6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/*
 * mygram-droid: Android TV client for Foldergram.
 * Copyright (C) 2026 Danilo M. <danix@danix.xyz>
 *
 * 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<TileAdapter.Holder> {
	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<Tile> tiles;
	private final int widthDp, heightDp;

	TileAdapter(List<Tile> 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();
	}
}