That fuck shit the fascists are using
1package org.tm.archive.components;
2
3import android.content.Context;
4import android.content.res.TypedArray;
5import android.graphics.Canvas;
6import android.graphics.Color;
7import android.os.Bundle;
8import android.os.Parcelable;
9import android.util.AttributeSet;
10import android.view.View;
11import android.view.ViewGroup;
12import android.widget.FrameLayout;
13import android.widget.TextView;
14
15import androidx.annotation.NonNull;
16import androidx.annotation.Nullable;
17import androidx.annotation.StringRes;
18
19import com.bumptech.glide.RequestManager;
20
21import org.signal.ringrtc.CallLinkRootKey;
22import org.tm.archive.R;
23import org.tm.archive.calls.links.CallLinks;
24import org.tm.archive.conversation.colors.AvatarColorHash;
25import org.tm.archive.linkpreview.LinkPreview;
26import org.tm.archive.linkpreview.LinkPreviewRepository;
27import org.tm.archive.mms.ImageSlide;
28import org.tm.archive.mms.SlidesClickedListener;
29import org.tm.archive.recipients.Recipient;
30import org.tm.archive.util.Util;
31import org.tm.archive.util.ViewUtil;
32import org.tm.archive.util.views.Stub;
33
34import java.text.DateFormat;
35import java.text.SimpleDateFormat;
36import java.util.Locale;
37
38import okhttp3.HttpUrl;
39
40/**
41 * The view shown in the compose box or conversation that represents the state of the link preview.
42 */
43public class LinkPreviewView extends FrameLayout {
44
45 private static final String STATE_ROOT = "linkPreviewView.state.root";
46 private static final String STATE_STATE = "linkPreviewView.state.state";
47
48 private static final int TYPE_CONVERSATION = 0;
49 private static final int TYPE_COMPOSE = 1;
50
51 private ViewGroup container;
52 private Stub<OutlinedThumbnailView> thumbnail;
53 private TextView title;
54 private TextView description;
55 private TextView site;
56 private View divider;
57 private View closeButton;
58 private View spinner;
59 private TextView noPreview;
60
61 private int type;
62 private int defaultRadius;
63 private CornerMask cornerMask;
64 private CloseClickedListener closeClickedListener;
65 private LinkPreviewViewThumbnailState thumbnailState = new LinkPreviewViewThumbnailState();
66
67 public LinkPreviewView(Context context) {
68 super(context);
69 init(null);
70 }
71
72 public LinkPreviewView(Context context, @Nullable AttributeSet attrs) {
73 super(context, attrs);
74 init(attrs);
75 }
76
77 private void init(@Nullable AttributeSet attrs) {
78 inflate(getContext(), R.layout.link_preview, this);
79
80 container = findViewById(R.id.linkpreview_container);
81 thumbnail = new Stub<>(findViewById(R.id.linkpreview_thumbnail));
82 title = findViewById(R.id.linkpreview_title);
83 description = findViewById(R.id.linkpreview_description);
84 site = findViewById(R.id.linkpreview_site);
85 divider = findViewById(R.id.linkpreview_divider);
86 spinner = findViewById(R.id.linkpreview_progress_wheel);
87 closeButton = findViewById(R.id.linkpreview_close);
88 noPreview = findViewById(R.id.linkpreview_no_preview);
89 defaultRadius = getResources().getDimensionPixelSize(R.dimen.thumbnail_default_radius);
90 cornerMask = new CornerMask(this);
91
92 if (attrs != null) {
93 TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.LinkPreviewView, 0, 0);
94 type = typedArray.getInt(R.styleable.LinkPreviewView_linkpreview_type, 0);
95 typedArray.recycle();
96 }
97
98 if (type == TYPE_COMPOSE) {
99 container.setBackgroundColor(Color.TRANSPARENT);
100 container.setPadding(0, 0, 0, 0);
101 divider.setVisibility(VISIBLE);
102 closeButton.setVisibility(VISIBLE);
103 title.setMaxLines(2);
104 description.setMaxLines(2);
105
106 closeButton.setOnClickListener(v -> {
107 if (closeClickedListener != null) {
108 closeClickedListener.onCloseClicked();
109 }
110 });
111 }
112
113 setWillNotDraw(false);
114 }
115
116 @Override
117 protected @NonNull Parcelable onSaveInstanceState() {
118 Parcelable root = super.onSaveInstanceState();
119 Bundle bundle = new Bundle();
120
121 bundle.putParcelable(STATE_ROOT, root);
122 bundle.putParcelable(STATE_STATE, thumbnailState);
123
124 return bundle;
125 }
126
127 @Override
128 protected void onRestoreInstanceState(Parcelable state) {
129 if (state instanceof Bundle) {
130 Parcelable root = ((Bundle) state).getParcelable(STATE_ROOT);
131 thumbnailState = ((Bundle) state).getParcelable(STATE_STATE);
132
133 thumbnailState.applyState(thumbnail);
134 super.onRestoreInstanceState(root);
135 } else {
136 super.onRestoreInstanceState(state);
137 }
138 }
139
140 @Override
141 protected void dispatchDraw(Canvas canvas) {
142 super.dispatchDraw(canvas);
143 if (type == TYPE_COMPOSE) return;
144
145 cornerMask.mask(canvas);
146 }
147
148 public void setLoading() {
149 title.setVisibility(GONE);
150 site.setVisibility(GONE);
151 description.setVisibility(GONE);
152 thumbnail.setVisibility(GONE);
153 spinner.setVisibility(VISIBLE);
154 noPreview.setVisibility(INVISIBLE);
155 }
156
157 public void setNoPreview(@Nullable LinkPreviewRepository.Error customError) {
158 title.setVisibility(GONE);
159 site.setVisibility(GONE);
160 thumbnail.setVisibility(GONE);
161 spinner.setVisibility(GONE);
162 noPreview.setVisibility(VISIBLE);
163 noPreview.setText(getLinkPreviewErrorString(customError));
164 }
165
166 public void setLinkPreview(@NonNull RequestManager requestManager, @NonNull LinkPreview linkPreview, boolean showThumbnail) {
167 setLinkPreview(requestManager, linkPreview, showThumbnail, true, false);
168 }
169
170 public void setLinkPreview(@NonNull RequestManager requestManager, @NonNull LinkPreview linkPreview, boolean showThumbnail, boolean showDescription, boolean scheduleMessageMode) {
171 spinner.setVisibility(GONE);
172 noPreview.setVisibility(GONE);
173
174 CallLinkRootKey callLinkRootKey = CallLinks.parseUrl(linkPreview.getUrl());
175 if (!Util.isEmpty(linkPreview.getTitle())) {
176 title.setText(linkPreview.getTitle());
177 title.setVisibility(VISIBLE);
178 } else if (callLinkRootKey != null) {
179 title.setText(R.string.Recipient_signal_call);
180 title.setVisibility(VISIBLE);
181 } else {
182 title.setVisibility(GONE);
183 }
184
185 if (showDescription && !Util.isEmpty(linkPreview.getDescription())) {
186 description.setText(linkPreview.getDescription());
187 description.setVisibility(VISIBLE);
188 } else if (callLinkRootKey != null) {
189 description.setText(R.string.LinkPreviewView__use_this_link_to_join_a_signal_call);
190 description.setVisibility(VISIBLE);
191 } else {
192 description.setVisibility(GONE);
193 }
194
195 String domain = null;
196
197 if (!Util.isEmpty(linkPreview.getUrl())) {
198 HttpUrl url = HttpUrl.parse(linkPreview.getUrl());
199 if (url != null) {
200 domain = url.topPrivateDomain();
201 }
202 }
203
204 if (domain != null && linkPreview.getDate() > 0) {
205 site.setText(getContext().getString(R.string.LinkPreviewView_domain_date, domain, formatDate(linkPreview.getDate())));
206 site.setVisibility(VISIBLE);
207 } else if (domain != null) {
208 site.setText(domain);
209 site.setVisibility(VISIBLE);
210 } else if (linkPreview.getDate() > 0) {
211 site.setText(formatDate(linkPreview.getDate()));
212 site.setVisibility(VISIBLE);
213 } else {
214 site.setVisibility(GONE);
215 }
216
217 if (showThumbnail && linkPreview.getThumbnail().isPresent()) {
218 thumbnail.setVisibility(VISIBLE);
219 thumbnailState.applyState(thumbnail);
220 thumbnail.get().setImageResource(requestManager, new ImageSlide(linkPreview.getThumbnail().get()), type == TYPE_CONVERSATION && !scheduleMessageMode, false);
221 thumbnail.get().showSecondaryText(false);
222 } else if (callLinkRootKey != null) {
223 thumbnail.setVisibility(VISIBLE);
224 thumbnailState.applyState(thumbnail);
225 thumbnail.get().setImageDrawable(
226 requestManager,
227 Recipient.DEFAULT_FALLBACK_PHOTO_PROVIDER
228 .getPhotoForCallLink()
229 .asDrawable(getContext(),
230 AvatarColorHash.forCallLink(callLinkRootKey.getKeyBytes()))
231 );
232 thumbnail.get().showSecondaryText(false);
233 } else {
234 thumbnail.setVisibility(GONE);
235 }
236 }
237
238 public void setCorners(int topStart, int topEnd) {
239 if (ViewUtil.isRtl(this)) {
240 cornerMask.setRadii(topEnd, topStart, 0, 0);
241 thumbnailState = thumbnailState.copy(
242 defaultRadius,
243 topEnd,
244 defaultRadius,
245 defaultRadius,
246 thumbnailState.getDownloadListener()
247 );
248 thumbnailState.applyState(thumbnail);
249 } else {
250 cornerMask.setRadii(topStart, topEnd, 0, 0);
251 thumbnailState.copy(
252 topStart,
253 defaultRadius,
254 defaultRadius,
255 defaultRadius,
256 thumbnailState.getDownloadListener()
257 );
258 thumbnailState.applyState(thumbnail);
259 }
260 postInvalidate();
261 }
262
263 public void setCloseClickedListener(@Nullable CloseClickedListener closeClickedListener) {
264 this.closeClickedListener = closeClickedListener;
265 }
266
267 public void setDownloadClickedListener(SlidesClickedListener listener) {
268 thumbnailState = thumbnailState.withDownloadListener(listener);
269 thumbnailState.applyState(thumbnail);
270 }
271
272 private @StringRes static int getLinkPreviewErrorString(@Nullable LinkPreviewRepository.Error customError) {
273 return customError == LinkPreviewRepository.Error.GROUP_LINK_INACTIVE ? R.string.LinkPreviewView_this_group_link_is_not_active
274 : R.string.LinkPreviewView_no_link_preview_available;
275 }
276
277 private static String formatDate(long date) {
278 DateFormat dateFormat = new SimpleDateFormat("MMM dd, yyyy", Locale.getDefault());
279 return dateFormat.format(date);
280 }
281
282 public interface CloseClickedListener {
283 void onCloseClicked();
284 }
285}