aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main/java/mygram/droid/HomeRows.java
blob: 9615f6f41ac79ec9eb84a3795afee3f0bf01ea9c (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
/*
 * 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.app.Activity;
import android.content.Context;
import android.view.Gravity;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/** Home: one row per folder, a random sample of its posts, then a Continue tile. */
final class HomeRows extends RecyclerView.Adapter<HomeRows.Row> {
	private static final int SAMPLE = 10;

	static final class Row extends RecyclerView.ViewHolder {
		final TextView title;
		final ImageView avatar;
		final RecyclerView tiles;
		/** Backing list of the row's one adapter: rebinds refill it instead of replacing the adapter. */
		final List<TileAdapter.Tile> list = new ArrayList<>();

		Row(LinearLayout v, ImageView avatar, TextView title, RecyclerView tiles) {
			super(v);
			this.avatar = avatar;
			this.title = title;
			this.tiles = tiles;
			tiles.setAdapter(new TileAdapter(list, Ui.POST_W, Ui.POST_H));
		}
	}

	private final Activity activity;
	private final List<Api.Folder> folders;
	private final Map<String, List<Post>> samples = new HashMap<>();

	HomeRows(Activity activity, List<Api.Folder> folders) {
		this.activity = activity;
		this.folders = folders;
	}

	@Override
	public Row onCreateViewHolder(ViewGroup parent, int type) {
		Context c = parent.getContext();
		LinearLayout v = new LinearLayout(c);
		v.setOrientation(LinearLayout.VERTICAL);
		v.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
				ViewGroup.LayoutParams.WRAP_CONTENT));
		LinearLayout head = new LinearLayout(c);
		head.setGravity(Gravity.CENTER_VERTICAL);
		head.setPadding(Ui.dp(c, 36), Ui.dp(c, 16), 0, 0);
		ImageView avatar = Ui.avatar(c, 32);
		((LinearLayout.LayoutParams) avatar.getLayoutParams()).rightMargin = Ui.dp(c, 12);
		head.addView(avatar);
		TextView title = Ui.text(c, "", 18);
		head.addView(title);
		v.addView(head);
		RecyclerView tiles = Ui.list(c, RecyclerView.HORIZONTAL);
		v.addView(tiles, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
				Ui.dp(c, Ui.POST_H + 24)));
		return new Row(v, avatar, title, tiles);
	}

	@Override
	public void onBindViewHolder(Row row, int position) {
		Api.Folder f = folders.get(position);
		row.title.setText(f.name);
		Ui.setAvatar(row.avatar, f.avatarUrl);
		List<Post> posts = samples.get(f.slug);
		if (posts == null) {
			posts = List.of();
			samples.put(f.slug, posts); // marks it loading, so it is fetched once
			Api.async(() -> Api.folderSample(f, SAMPLE), p -> {
				samples.put(f.slug, p);
				notifyItemChanged(folders.indexOf(f), Boolean.TRUE); // payload: keep the holder, so focus stays
			}, e -> {
				// the row keeps only its Continue tile
			});
		}
		List<TileAdapter.Tile> tiles = row.list;
		tiles.clear();
		for (Post p : posts)
			tiles.add(TileAdapter.post(p, () -> open(f, p)));
		tiles.add(new TileAdapter.Tile(null, "Continue", R.drawable.ic_arrow_forward, -1,
				() -> FolderActivity.open(activity, f)));
		row.tiles.getAdapter().notifyDataSetChanged();
	}

	@Override
	public int getItemCount() {
		return folders.size();
	}

	/** Viewer at p at once; the rest of the folder pages in lazily, in random page order. */
	private void open(Api.Folder f, Post p) {
		Playlist.open(activity, new ArrayList<>(List.of(p)), 0, Api.folderPages(f.slug, f.count));
	}

	/** Rebinds visible tiles so hearts follow likes changed in the viewer. */
	void refreshHearts(RecyclerView list) {
		for (int i = 0; i < list.getChildCount(); i++) {
			RecyclerView.Adapter<?> a = ((Row) list.getChildViewHolder(list.getChildAt(i))).tiles.getAdapter();
			if (a != null)
				a.notifyItemRangeChanged(0, a.getItemCount());
		}
	}
}