That fuck shit the fascists are using
1package org.signal.pagingtest;
2
3import androidx.annotation.NonNull;
4import androidx.annotation.Nullable;
5import androidx.appcompat.app.AppCompatActivity;
6import androidx.lifecycle.ViewModelProvider;
7import androidx.recyclerview.widget.DiffUtil;
8import androidx.recyclerview.widget.LinearLayoutManager;
9import androidx.recyclerview.widget.RecyclerView;
10
11import android.os.Bundle;
12import android.view.LayoutInflater;
13import android.view.View;
14import android.view.ViewGroup;
15import android.widget.TextView;
16
17import org.signal.paging.PagingController;
18
19import java.util.ArrayList;
20import java.util.List;
21import java.util.Objects;
22import java.util.Optional;
23
24public class MainActivity extends AppCompatActivity implements EventListener {
25
26 private MainViewModel viewModel;
27
28 @Override
29 protected void onCreate(Bundle savedInstanceState) {
30 super.onCreate(savedInstanceState);
31 setContentView(R.layout.activity_main);
32
33 MyAdapter adapter = new MyAdapter(this);
34 RecyclerView list = findViewById(R.id.list);
35 LinearLayoutManager layoutManager = new LinearLayoutManager(this);
36
37 list.setAdapter(adapter);
38 list.setLayoutManager(layoutManager);
39
40 viewModel = new ViewModelProvider(this, new ViewModelProvider.NewInstanceFactory()).get(MainViewModel.class);
41 adapter.setPagingController(viewModel.getPagingController());
42 viewModel.getList().observe(this, newList -> {
43 adapter.submitList(newList);
44 });
45
46 findViewById(R.id.invalidate_btn).setOnClickListener(v -> {
47 viewModel.getPagingController().onDataInvalidated();
48 });
49
50 findViewById(R.id.down250_btn).setOnClickListener(v -> {
51 int target = Math.min(adapter.getItemCount() - 1, layoutManager.findFirstVisibleItemPosition() + 250);
52 layoutManager.scrollToPosition(target);
53 });
54
55 findViewById(R.id.up250_btn).setOnClickListener(v -> {
56 int target = Math.max(0, layoutManager.findFirstVisibleItemPosition() - 250);
57 layoutManager.scrollToPosition(target);
58 });
59
60 findViewById(R.id.prepend_btn).setOnClickListener(v -> {
61 viewModel.prependItems();
62 });
63 }
64
65 @Override
66 public void onItemClicked(String key) {
67 viewModel.onItemClicked(key);
68 }
69
70 static class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
71
72 private final static int TYPE_NORMAL = 1;
73 private final static int TYPE_PLACEHOLDER = -1;
74
75 private final EventListener listener;
76 private final List<Item> data;
77
78 private PagingController<String> controller;
79
80 public MyAdapter(@NonNull EventListener listener) {
81 this.listener = listener;
82 this.data = new ArrayList<>();
83
84 setHasStableIds(true);
85 }
86
87 @Override
88 public int getItemViewType(int position) {
89 return getItem(position) == null ? TYPE_PLACEHOLDER : TYPE_NORMAL;
90 }
91
92 @Override
93 public int getItemCount() {
94 return data.size();
95 }
96
97 @Override
98 public long getItemId(int position) {
99 Item item = getItem(position);
100 if (item != null) {
101 return item.key.hashCode();
102 } else {
103 return 0;
104 }
105 }
106
107 @Override
108 public @NonNull MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
109 switch (viewType) {
110 case TYPE_NORMAL:
111 case TYPE_PLACEHOLDER:
112 return new MyViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false));
113 default:
114 throw new AssertionError();
115 }
116 }
117
118 @Override
119 public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
120 holder.bind(getItem(position), position, listener);
121 }
122
123 private Item getItem(int index) {
124 if (controller != null) {
125 controller.onDataNeededAroundIndex(index);
126 }
127 return data.get(index);
128 }
129
130 void setPagingController(PagingController<String> pagingController) {
131 this.controller = pagingController;
132 }
133
134 void submitList(List<Item> list) {
135 DiffUtil.DiffResult result = DiffUtil.calculateDiff(new DiffUtil.Callback() {
136 @Override
137 public int getOldListSize() {
138 return data.size();
139 }
140
141 @Override
142 public int getNewListSize() {
143 return list.size();
144 }
145
146 @Override
147 public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
148 String oldKey = Optional.ofNullable(data.get(oldItemPosition)).map(item -> item.key).orElse(null);
149 String newKey = Optional.ofNullable(list.get(newItemPosition)).map(item -> item.key).orElse(null);
150
151 return Objects.equals(oldKey, newKey);
152 }
153
154 @Override
155 public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
156 Long oldKey = Optional.ofNullable(data.get(oldItemPosition)).map(item -> item.timestamp).orElse(null);
157 Long newKey = Optional.ofNullable(list.get(newItemPosition)).map(item -> item.timestamp).orElse(null);
158
159 return Objects.equals(oldKey, newKey);
160 }
161 }, false);
162
163 result.dispatchUpdatesTo(this);
164
165 data.clear();
166 data.addAll(list);
167 }
168 }
169
170 static class MyViewHolder extends RecyclerView.ViewHolder {
171
172 TextView textView;
173
174 public MyViewHolder(@NonNull View itemView) {
175 super(itemView);
176 textView = itemView.findViewById(R.id.text);
177 }
178
179 void bind(@Nullable Item item, int position, @NonNull EventListener listener) {
180 if (item != null) {
181 textView.setText(position + " | " + item.key.substring(0, 13) + " | " + System.currentTimeMillis());
182 textView.setOnClickListener(v -> {
183 listener.onItemClicked(item.key);
184 });
185 } else {
186 textView.setText(position + " | PLACEHOLDER");
187 textView.setOnClickListener(null);
188 }
189 }
190 }
191}