|
46 | 46 | import android.graphics.drawable.Drawable;
|
47 | 47 | import android.graphics.fonts.Font;
|
48 | 48 | import android.graphics.fonts.FontFamily;
|
| 49 | +import android.graphics.fonts.FontStyle; |
49 | 50 | import android.graphics.fonts.SystemFonts;
|
50 | 51 | import android.net.Uri;
|
51 | 52 | import android.os.Build;
|
|
100 | 101 | import android.view.accessibility.AccessibilityEvent;
|
101 | 102 | import android.view.accessibility.AccessibilityManager;
|
102 | 103 | import android.view.animation.AccelerateInterpolator;
|
| 104 | +import android.view.animation.Animation; |
103 | 105 | import android.view.animation.DecelerateInterpolator;
|
| 106 | +import android.view.animation.Interpolator; |
104 | 107 | import android.view.animation.OvershootInterpolator;
|
105 | 108 | import android.view.inputmethod.InputMethodManager;
|
106 | 109 | import android.view.inputmethod.InputMethodSubtype;
|
@@ -304,15 +307,25 @@ public static Typeface bold() {
|
304 | 307 | public static Pattern LONG_BAD_CHARS_PATTERN = null;
|
305 | 308 | public static Pattern BAD_CHARS_MESSAGE_PATTERN = null;
|
306 | 309 | public static Pattern BAD_CHARS_MESSAGE_LONG_PATTERN = null;
|
| 310 | + public static Pattern REMOVE_MULTIPLE_DIACRITICS = null; |
307 | 311 | private static Pattern singleTagPatter = null;
|
308 | 312 |
|
| 313 | + public static String removeDiacritics(String str) { |
| 314 | + if (str == null) return null; |
| 315 | + if (REMOVE_MULTIPLE_DIACRITICS == null) return str; |
| 316 | + Matcher matcher = REMOVE_MULTIPLE_DIACRITICS.matcher(str); |
| 317 | + if (matcher == null) return str; |
| 318 | + return matcher.replaceAll("$1"); |
| 319 | + } |
| 320 | + |
309 | 321 | static {
|
310 | 322 | try {
|
311 | 323 | final String GOOD_IRI_CHAR = "a-zA-Z0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF";
|
312 | 324 | BAD_CHARS_PATTERN = Pattern.compile("[\u2500-\u25ff]");
|
313 | 325 | LONG_BAD_CHARS_PATTERN = Pattern.compile("[\u4e00-\u9fff]");
|
314 |
| - BAD_CHARS_MESSAGE_LONG_PATTERN = Pattern.compile("[\u0300-\u036f\u2066-\u2067]+"); |
| 326 | + BAD_CHARS_MESSAGE_LONG_PATTERN = Pattern.compile("[\u0300-\u036f\u2066-\u2067]"); |
315 | 327 | BAD_CHARS_MESSAGE_PATTERN = Pattern.compile("[\u2066-\u2067]+");
|
| 328 | + REMOVE_MULTIPLE_DIACRITICS = Pattern.compile("([\\u0300-\\u036f]{1,2})[\\u0300-\\u036f]+"); |
316 | 329 | final Pattern IP_ADDRESS = Pattern.compile(
|
317 | 330 | "((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4]"
|
318 | 331 | + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]"
|
@@ -564,6 +577,34 @@ public void updateDrawState(TextPaint textPaint) {
|
564 | 577 | return spannableStringBuilder;
|
565 | 578 | }
|
566 | 579 |
|
| 580 | + |
| 581 | + public static SpannableStringBuilder replaceMultipleTags(String str, Runnable ...runnables) { |
| 582 | + SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(str); |
| 583 | + for (int i = 0; i < runnables.length; ++i) { |
| 584 | + Runnable runnable = runnables[i]; |
| 585 | + |
| 586 | + int start = charSequenceIndexOf(spannableStringBuilder, "**"); |
| 587 | + int end = charSequenceIndexOf(spannableStringBuilder, "**", start + 2); |
| 588 | + if (start < 0 || end < 0) break; |
| 589 | + |
| 590 | + spannableStringBuilder.delete(start, start + 2); |
| 591 | + end = end - 2; |
| 592 | + spannableStringBuilder.delete(end, end + 2); |
| 593 | + spannableStringBuilder.setSpan(new ClickableSpan() { |
| 594 | + @Override |
| 595 | + public void updateDrawState(@NonNull TextPaint ds) { |
| 596 | + super.updateDrawState(ds); |
| 597 | + ds.setUnderlineText(false); |
| 598 | + } |
| 599 | + @Override |
| 600 | + public void onClick(@NonNull View widget) { |
| 601 | + if (runnable != null) runnable.run(); |
| 602 | + } |
| 603 | + }, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); |
| 604 | + } |
| 605 | + return spannableStringBuilder; |
| 606 | + } |
| 607 | + |
567 | 608 | public static SpannableStringBuilder replaceSingleLink(String str, int color) {
|
568 | 609 | return replaceSingleLink(str, color, null);
|
569 | 610 | }
|
@@ -1840,13 +1881,17 @@ public String getRawType(boolean first) {
|
1840 | 1881 | }
|
1841 | 1882 |
|
1842 | 1883 | public String getType() {
|
1843 |
| - if (type == 5) { |
1844 |
| - return LocaleController.getString("ContactBirthday", R.string.ContactBirthday); |
| 1884 | + if (type == 4) { |
| 1885 | + return LocaleController.getString(R.string.ContactNote); |
| 1886 | + } else if (type == 3) { |
| 1887 | + return LocaleController.getString(R.string.ContactUrl); |
| 1888 | + } else if (type == 5) { |
| 1889 | + return LocaleController.getString(R.string.ContactBirthday); |
1845 | 1890 | } else if (type == 6) {
|
1846 | 1891 | if ("ORG".equalsIgnoreCase(getRawType(true))) {
|
1847 |
| - return LocaleController.getString("ContactJob", R.string.ContactJob); |
| 1892 | + return LocaleController.getString(R.string.ContactJob); |
1848 | 1893 | } else {
|
1849 |
| - return LocaleController.getString("ContactJobTitle", R.string.ContactJobTitle); |
| 1894 | + return LocaleController.getString(R.string.ContactJobTitle); |
1850 | 1895 | }
|
1851 | 1896 | }
|
1852 | 1897 | int idx = fullData.indexOf(':');
|
@@ -4674,6 +4719,15 @@ public static void lerp(Rect a, Rect b, float f, Rect to) {
|
4674 | 4719 | }
|
4675 | 4720 | }
|
4676 | 4721 |
|
| 4722 | + public static void lerpCentered(RectF a, RectF b, float f, RectF to) { |
| 4723 | + if (to == null) return; |
| 4724 | + final float cx = lerp(a.centerX(), b.centerX(), f); |
| 4725 | + final float cy = lerp(a.centerY(), b.centerY(), f); |
| 4726 | + final float hw = lerp(a.width(), b.width(), Math.min(1, f)) / 2f; |
| 4727 | + final float hh = lerp(a.height(), b.height(), Math.min(1, f)) / 2f; |
| 4728 | + to.set(cx - hw, cy - hh, cx + hw, cy + hh); |
| 4729 | + } |
| 4730 | + |
4677 | 4731 | public static void lerp(int[] a, int[] b, float f, int[] to) {
|
4678 | 4732 | if (to == null) return;
|
4679 | 4733 | for (int i = 0; i < to.length; ++i) {
|
@@ -5840,4 +5894,71 @@ public static void vibrate(View view) {
|
5840 | 5894 | } catch (Exception ignore) {}
|
5841 | 5895 | }
|
5842 | 5896 |
|
| 5897 | + public static void applySpring(Animator anim, float stiffness, float damping) { |
| 5898 | + applySpring(anim, stiffness, damping, 1); |
| 5899 | + } |
| 5900 | + |
| 5901 | + public static void applySpring(Animator anim, float stiffness, float damping, float mass) { |
| 5902 | + final double delta = damping / (2.0 * Math.sqrt(stiffness * mass)); |
| 5903 | + final double undampedFrequency = Math.sqrt(stiffness / mass); |
| 5904 | + final double omega_0 = Math.sqrt(stiffness / mass); |
| 5905 | + final double zeta = damping / (2 * Math.sqrt(stiffness * mass)); |
| 5906 | + final double threshold = 0.0025; |
| 5907 | + final double duration = Math.log(threshold) / (-zeta * omega_0); |
| 5908 | + anim.setDuration((long) (duration * 1000L)); |
| 5909 | + anim.setInterpolator(new Interpolator() { |
| 5910 | + @Override |
| 5911 | + public float getInterpolation(float t) { |
| 5912 | + if (delta < 1) { |
| 5913 | + final double dampedFrequency = undampedFrequency * Math.sqrt(1 - delta * delta); |
| 5914 | + return (float) (1 - Math.exp(-delta * undampedFrequency * t) * |
| 5915 | + (Math.cos(dampedFrequency * t) + (delta * undampedFrequency / dampedFrequency) * Math.sin(dampedFrequency * t))); |
| 5916 | + } else { |
| 5917 | + final double a = -delta * undampedFrequency * t; |
| 5918 | + return (float) (1 - (1 + a) * Math.exp(a)); |
| 5919 | + } |
| 5920 | + } |
| 5921 | + }); |
| 5922 | + } |
| 5923 | + |
| 5924 | + public static boolean isWebAppLink(String url) { |
| 5925 | + if (url == null) return false; |
| 5926 | + try { |
| 5927 | + Uri uri = Uri.parse(url); |
| 5928 | + final String scheme = uri.getScheme(); |
| 5929 | + if (scheme == null) return false; |
| 5930 | + final String path = uri.getPath(); |
| 5931 | + if (path == null) return false; |
| 5932 | + switch (scheme) { |
| 5933 | + case "http": |
| 5934 | + case "https": { |
| 5935 | + if (path.isEmpty()) return false; |
| 5936 | + ArrayList<String> segments = new ArrayList<>(uri.getPathSegments()); |
| 5937 | + if (segments.size() > 0 && segments.get(0).equals("s")) { |
| 5938 | + segments.remove(0); |
| 5939 | + } |
| 5940 | + if (segments.size() > 0) { |
| 5941 | + if (segments.size() >= 3 && "s".equals(segments.get(1))) { |
| 5942 | + return false; |
| 5943 | + } else if (segments.size() > 1) { |
| 5944 | + return !TextUtils.isEmpty(segments.get(1)); |
| 5945 | + } else if (segments.size() == 1) { |
| 5946 | + return !TextUtils.isEmpty(uri.getQueryParameter("startapp")); |
| 5947 | + } |
| 5948 | + } |
| 5949 | + break; |
| 5950 | + } |
| 5951 | + case "tg": { |
| 5952 | + if (url.startsWith("tg:resolve") || url.startsWith("tg://resolve")) { |
| 5953 | + return !TextUtils.isEmpty(uri.getQueryParameter("appname")); |
| 5954 | + } |
| 5955 | + break; |
| 5956 | + } |
| 5957 | + } |
| 5958 | + } catch (Exception e) { |
| 5959 | + FileLog.e(e); |
| 5960 | + } |
| 5961 | + return false; |
| 5962 | + } |
| 5963 | + |
5843 | 5964 | }
|
0 commit comments