That fuck shit the fascists are using
1/**
2 * Copyright (C) 2015 Open Whisper Systems
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17package org.tm.archive.util;
18
19import android.annotation.SuppressLint;
20import android.app.Activity;
21import android.content.Context;
22import android.content.res.Resources;
23import android.os.Build;
24import android.util.TypedValue;
25import android.view.Gravity;
26import android.view.LayoutInflater;
27import android.view.View;
28import android.view.ViewGroup;
29import android.view.ViewStub;
30import android.view.ViewTreeObserver;
31import android.view.animation.AlphaAnimation;
32import android.view.animation.Animation;
33import android.view.inputmethod.InputMethodManager;
34import android.widget.EditText;
35import android.widget.TextView;
36
37import androidx.annotation.IdRes;
38import androidx.annotation.LayoutRes;
39import androidx.annotation.NonNull;
40import androidx.annotation.Nullable;
41import androidx.annotation.Px;
42import androidx.appcompat.app.AppCompatActivity;
43import androidx.appcompat.view.ContextThemeWrapper;
44import androidx.core.view.ViewCompat;
45import androidx.core.view.WindowInsetsCompat;
46import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
47import androidx.lifecycle.Lifecycle;
48
49import org.signal.core.util.concurrent.ListenableFuture;
50import org.signal.core.util.concurrent.SettableFuture;
51import org.tm.archive.util.views.Stub;
52
53public final class ViewUtil {
54
55 private ViewUtil() {
56 }
57
58 public static void setMinimumHeight(@NonNull View view, @Px int minimumHeight) {
59 if (view.getMinimumHeight() != minimumHeight) {
60 view.setMinimumHeight(minimumHeight);
61 }
62 }
63
64 public static void focusAndMoveCursorToEndAndOpenKeyboard(@NonNull EditText input) {
65 int numberLength = input.getText().length();
66 input.setSelection(numberLength, numberLength);
67
68 focusAndShowKeyboard(input);
69 }
70
71 public static void focusAndShowKeyboard(@NonNull View view) {
72 view.requestFocus();
73 if (view.hasWindowFocus()) {
74 showTheKeyboardNow(view);
75 } else {
76 view.getViewTreeObserver().addOnWindowFocusChangeListener(new ViewTreeObserver.OnWindowFocusChangeListener() {
77 @Override
78 public void onWindowFocusChanged(boolean hasFocus) {
79 if (hasFocus) {
80 showTheKeyboardNow(view);
81 view.getViewTreeObserver().removeOnWindowFocusChangeListener(this);
82 }
83 }
84 });
85 }
86 }
87
88 private static void showTheKeyboardNow(@NonNull View view) {
89 if (view.isFocused()) {
90 view.post(() -> {
91 InputMethodManager inputMethodManager = ServiceUtil.getInputMethodManager(view.getContext());
92 inputMethodManager.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
93 });
94 }
95 }
96
97 @SuppressWarnings("unchecked")
98 public static <T extends View> T inflateStub(@NonNull View parent, @IdRes int stubId) {
99 return (T)((ViewStub)parent.findViewById(stubId)).inflate();
100 }
101
102 public static <T extends View> Stub<T> findStubById(@NonNull Activity parent, @IdRes int resId) {
103 return new Stub<>(parent.findViewById(resId));
104 }
105
106 public static <T extends View> Stub<T> findStubById(@NonNull View parent, @IdRes int resId) {
107 return new Stub<>(parent.findViewById(resId));
108 }
109
110 private static Animation getAlphaAnimation(float from, float to, int duration) {
111 final Animation anim = new AlphaAnimation(from, to);
112 anim.setInterpolator(new FastOutSlowInInterpolator());
113 anim.setDuration(duration);
114 return anim;
115 }
116
117 public static void fadeIn(final @NonNull View view, final int duration) {
118 animateIn(view, getAlphaAnimation(0f, 1f, duration));
119 }
120
121 public static ListenableFuture<Boolean> fadeOut(final @NonNull View view, final int duration) {
122 return fadeOut(view, duration, View.GONE);
123 }
124
125 public static ListenableFuture<Boolean> fadeOut(@NonNull View view, int duration, int visibility) {
126 return animateOut(view, getAlphaAnimation(1f, 0f, duration), visibility);
127 }
128
129 public static ListenableFuture<Boolean> animateOut(final @NonNull View view, final @NonNull Animation animation) {
130 return animateOut(view, animation, View.GONE);
131 }
132
133 public static ListenableFuture<Boolean> animateOut(final @NonNull View view, final @NonNull Animation animation, final int visibility) {
134 final SettableFuture future = new SettableFuture();
135 if (view.getVisibility() == visibility) {
136 future.set(true);
137 } else {
138 view.clearAnimation();
139 animation.reset();
140 animation.setStartTime(0);
141 animation.setAnimationListener(new Animation.AnimationListener() {
142 @Override
143 public void onAnimationStart(Animation animation) {}
144
145 @Override
146 public void onAnimationRepeat(Animation animation) {}
147
148 @Override
149 public void onAnimationEnd(Animation animation) {
150 view.setVisibility(visibility);
151 future.set(true);
152 }
153 });
154 view.startAnimation(animation);
155 }
156 return future;
157 }
158
159 public static void animateIn(final @NonNull View view, final @NonNull Animation animation) {
160 if (view.getVisibility() == View.VISIBLE) return;
161
162 view.clearAnimation();
163 animation.reset();
164 animation.setStartTime(0);
165 view.setVisibility(View.VISIBLE);
166 view.startAnimation(animation);
167 }
168
169 @SuppressWarnings("unchecked")
170 public static <T extends View> T inflate(@NonNull LayoutInflater inflater,
171 @NonNull ViewGroup parent,
172 @LayoutRes int layoutResId)
173 {
174 return (T)(inflater.inflate(layoutResId, parent, false));
175 }
176
177 @SuppressLint("RtlHardcoded")
178 public static void setTextViewGravityStart(final @NonNull TextView textView, @NonNull Context context) {
179 if (isRtl(context)) {
180 textView.setGravity(Gravity.RIGHT);
181 } else {
182 textView.setGravity(Gravity.LEFT);
183 }
184 }
185
186 public static void mirrorIfRtl(View view, Context context) {
187 if (isRtl(context)) {
188 view.setScaleX(-1.0f);
189 }
190 }
191
192 public static boolean isLtr(@NonNull View view) {
193 return isLtr(view.getContext());
194 }
195
196 public static boolean isLtr(@NonNull Context context) {
197 return context.getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_LTR;
198 }
199
200 public static boolean isRtl(@NonNull View view) {
201 return isRtl(view.getContext());
202 }
203
204 public static boolean isRtl(@NonNull Context context) {
205 return context.getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
206 }
207
208 public static float pxToDp(float px) {
209 return px / Resources.getSystem().getDisplayMetrics().density;
210 }
211
212 public static int dpToPx(Context context, int dp) {
213 return (int)((dp * context.getResources().getDisplayMetrics().density) + 0.5);
214 }
215
216 public static int dpToPx(int dp) {
217 return Math.round(dp * Resources.getSystem().getDisplayMetrics().density);
218 }
219
220 public static int dpToSp(int dp) {
221 return (int) (dpToPx(dp) / Resources.getSystem().getDisplayMetrics().scaledDensity);
222 }
223
224 public static int spToPx(float sp) {
225 return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, Resources.getSystem().getDisplayMetrics());
226 }
227
228 public static void updateLayoutParams(@NonNull View view, int width, int height) {
229 view.getLayoutParams().width = width;
230 view.getLayoutParams().height = height;
231 view.requestLayout();
232 }
233
234 public static void updateLayoutParamsIfNonNull(@Nullable View view, int width, int height) {
235 if (view != null) {
236 updateLayoutParams(view, width, height);
237 }
238 }
239
240 public static void setVisibilityIfNonNull(@Nullable View view, int visibility) {
241 if (view != null) {
242 view.setVisibility(visibility);
243 }
244 }
245
246 public static int getLeftMargin(@NonNull View view) {
247 if (isLtr(view)) {
248 return ((ViewGroup.MarginLayoutParams) view.getLayoutParams()).leftMargin;
249 }
250 return ((ViewGroup.MarginLayoutParams) view.getLayoutParams()).rightMargin;
251 }
252
253 public static int getRightMargin(@NonNull View view) {
254 if (isLtr(view)) {
255 return ((ViewGroup.MarginLayoutParams) view.getLayoutParams()).rightMargin;
256 }
257 return ((ViewGroup.MarginLayoutParams) view.getLayoutParams()).leftMargin;
258 }
259
260 public static int getTopMargin(@NonNull View view) {
261 return ((ViewGroup.MarginLayoutParams) view.getLayoutParams()).topMargin;
262 }
263
264 public static int getBottomMargin(@NonNull View view) {
265 return ((ViewGroup.MarginLayoutParams) view.getLayoutParams()).bottomMargin;
266 }
267
268 public static void setLeftMargin(@NonNull View view, int margin) {
269 if (isLtr(view)) {
270 ((ViewGroup.MarginLayoutParams) view.getLayoutParams()).leftMargin = margin;
271 } else {
272 ((ViewGroup.MarginLayoutParams) view.getLayoutParams()).rightMargin = margin;
273 }
274 view.forceLayout();
275 view.requestLayout();
276 }
277
278 public static void setRightMargin(@NonNull View view, int margin) {
279 if (isLtr(view)) {
280 ((ViewGroup.MarginLayoutParams) view.getLayoutParams()).rightMargin = margin;
281 } else {
282 ((ViewGroup.MarginLayoutParams) view.getLayoutParams()).leftMargin = margin;
283 }
284 view.forceLayout();
285 view.requestLayout();
286 }
287
288 public static void setTopMargin(@NonNull View view, @Px int margin) {
289 setTopMargin(view, margin, true);
290 }
291
292 /**
293 * Sets the top margin of the view and optionally requests a new layout pass.
294 *
295 * @param view The view to set the margin on
296 * @param margin The margin to set
297 * @param requestLayout Whether requestLayout should be invoked on the view
298 */
299 public static void setTopMargin(@NonNull View view, @Px int margin, boolean requestLayout) {
300 ((ViewGroup.MarginLayoutParams) view.getLayoutParams()).topMargin = margin;
301
302 if (requestLayout) {
303 view.requestLayout();
304 }
305 }
306
307 public static void setBottomMargin(@NonNull View view, @Px int margin) {
308 setBottomMargin(view, margin, true);
309 }
310
311 /**
312 * Sets the bottom margin of the view and optionally requests a new layout pass.
313 *
314 * @param view The view to set the margin on
315 * @param margin The margin to set
316 * @param requestLayout Whether requestLayout should be invoked on the view
317 */
318 public static void setBottomMargin(@NonNull View view, @Px int margin, boolean requestLayout) {
319 ((ViewGroup.MarginLayoutParams) view.getLayoutParams()).bottomMargin = margin;
320 if (requestLayout) {
321 view.requestLayout();
322 }
323 }
324
325 public static int getWidth(@NonNull View view) {
326 return view.getLayoutParams().width;
327 }
328
329 public static void setPaddingTop(@NonNull View view, int padding) {
330 view.setPadding(view.getPaddingLeft(), padding, view.getPaddingRight(), view.getPaddingBottom());
331 }
332
333 public static void setPaddingBottom(@NonNull View view, int padding) {
334 view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), view.getPaddingRight(), padding);
335 }
336
337 public static void setPadding(@NonNull View view, int padding) {
338 view.setPadding(padding, padding, padding, padding);
339 }
340
341 public static void setPaddingStart(@NonNull View view, int padding) {
342 if (isLtr(view)) {
343 view.setPadding(padding, view.getPaddingTop(), view.getPaddingRight(), view.getPaddingBottom());
344 } else {
345 view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), padding, view.getPaddingBottom());
346 }
347 }
348
349 public static void setPaddingEnd(@NonNull View view, int padding) {
350 if (isLtr(view)) {
351 view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), padding, view.getPaddingBottom());
352 } else {
353 view.setPadding(padding, view.getPaddingTop(), view.getPaddingRight(), view.getPaddingBottom());
354 }
355 }
356
357 public static boolean isPointInsideView(@NonNull View view, float x, float y) {
358 int[] location = new int[2];
359
360 view.getLocationOnScreen(location);
361
362 int viewX = location[0];
363 int viewY = location[1];
364
365 return x > viewX && x < viewX + view.getWidth() &&
366 y > viewY && y < viewY + view.getHeight();
367 }
368
369 public static int getStatusBarHeight(@NonNull View view) {
370 final WindowInsetsCompat rootWindowInsets = ViewCompat.getRootWindowInsets(view);
371 if (Build.VERSION.SDK_INT > 29 && rootWindowInsets != null) {
372 return rootWindowInsets.getInsets(WindowInsetsCompat.Type.statusBars()).top;
373 } else {
374 int result = 0;
375 int resourceId = view.getResources().getIdentifier("status_bar_height", "dimen", "android");
376 if (resourceId > 0) {
377 result = view.getResources().getDimensionPixelSize(resourceId);
378 }
379 return result;
380 }
381 }
382
383 public static int getNavigationBarHeight(@NonNull View view) {
384 final WindowInsetsCompat rootWindowInsets = ViewCompat.getRootWindowInsets(view);
385 if (Build.VERSION.SDK_INT > 29 && rootWindowInsets != null) {
386 return rootWindowInsets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom;
387 } else {
388 int result = 0;
389 int resourceId = view.getResources().getIdentifier("navigation_bar_height", "dimen", "android");
390 if (resourceId > 0) {
391 result = view.getResources().getDimensionPixelSize(resourceId);
392 }
393 return result;
394 }
395 }
396
397 public static void hideKeyboard(@NonNull Context context, @NonNull View view) {
398 InputMethodManager inputManager = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE);
399 inputManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
400 }
401
402 /**
403 * Enables or disables a view and all child views recursively.
404 */
405 public static void setEnabledRecursive(@NonNull View view, boolean enabled) {
406 view.setEnabled(enabled);
407 if (view instanceof ViewGroup) {
408 ViewGroup viewGroup = (ViewGroup) view;
409 for (int i = 0; i < viewGroup.getChildCount(); i++) {
410 setEnabledRecursive(viewGroup.getChildAt(i), enabled);
411 }
412 }
413 }
414
415 public static @Nullable Lifecycle getActivityLifecycle(@NonNull View view) {
416 return getActivityLifecycle(view.getContext());
417 }
418
419 private static @Nullable Lifecycle getActivityLifecycle(@Nullable Context context) {
420 if (context instanceof ContextThemeWrapper) {
421 return getActivityLifecycle(((ContextThemeWrapper) context).getBaseContext());
422 }
423
424 if (context instanceof AppCompatActivity) {
425 return ((AppCompatActivity) context).getLifecycle();
426 }
427
428 return null;
429 }
430}