<commit_before>package cgeo.geocaching.utils;

import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.R;
import cgeo.geocaching.databinding.DialogTitleButtonButtonBinding;
import cgeo.geocaching.databinding.EmojiselectorBinding;
import cgeo.geocaching.maps.CacheMarker;
import cgeo.geocaching.models.Geocache;
import cgeo.geocaching.storage.extension.EmojiLRU;
import cgeo.geocaching.storage.extension.OneTimeDialogs;
import cgeo.geocaching.ui.ViewUtils;
import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.functions.Action1;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.graphics.drawable.BitmapDrawable;
import android.os.Build;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.Pair;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import java.util.HashMap;
import java.util.Map;

import com.google.android.material.button.MaterialButton;
import org.apache.commons.lang3.builder.HashCodeBuilder;

public class EmojiUtils {

    public static final int NO_EMOJI = 0;

    // internal consts for calculated circles
    private static final int COLOR_VALUES = 3;  // supported # of different values per RGB
    private static final int COLOR_SPREAD = 127;
    private static final int COLOR_OFFSET = 0;
    private static final int OPACITY_VALUES = 5;
    private static final int OPACITY_SPREAD = 51;
    private static final int CUSTOM_SET_SIZE_PER_OPACITY = COLOR_VALUES * COLOR_VALUES * COLOR_VALUES;
    private static final int CUSTOM_SET_SIZE = CUSTOM_SET_SIZE_PER_OPACITY * OPACITY_VALUES;

    // internal consts for plain numbers
    private static final int NUMBER_START = 0x30;
    private static final int NUMBER_END = 0x39;

    // Unicode custom glyph area needed/supported by this class
    private static final int CUSTOM_ICONS_START = 0xe000;
    private static final int CUSTOM_ICONS_END = CUSTOM_ICONS_START + CUSTOM_SET_SIZE - 1; // max. possible value by Unicode definition: 0xf8ff;
    private static final int CUSTOM_ICONS_START_CIRCLES = CUSTOM_ICONS_START;

    // Select emoji variation for unicode characters, see https://emojipedia.org/variation-selector-16/
    private static final int VariationSelectorEmoji = 0xfe0f;

    // list of emojis supported by the EmojiPopup
    // should ideally be supported by the Android API level we have set as minimum (currently API 21 = Android 5),
    // but starting with API 23 (Android 6) the app automatically filters out characters not supported by their fonts
    // for a list of supported Unicode standards by API level see https://developer.android.com/guide/topics/resources/internationalization
    // for characters by Unicode version see https://unicode.org/emoji/charts-5.0/full-emoji-list.html (v5.0 - preferred compatibility standard based on our minAPI level)
    // The newest emoji standard can be found here: https://unicode.org/emoji/charts/full-emoji-list.html

    public static final int SMILEY_LIKE = 0x1f600;
    public static final int SMILEY_LOVE = 0x1f499;
    public static final int SMILEY_MONOCLE = 0x1f453;
    public static final int SPARKLES = 0x2728;


    private static final EmojiSet[] symbols = {
            // category symbols
            new EmojiSet(0x2764, new int[]{
                    /* hearts */        0x2764, 0x1f9e1, 0x1f49b, 0x1f49a, 0x1f499, 0x1f49c, 0x1f90e, 0x1f5a4, 0x1f90d,
                    /* geometric */     0x1f7e5, 0x1f7e7, 0x1f7e8, 0x1f7e9, 0x1f7e6, 0x1f7ea, 0x1f7eb, 0x2b1b, 0x2b1c,
                    /* geometric */     0x1f536, 0x1f537,
                    /* events */        0x1f383, 0x1f380, 0x1f384, 0x1f389,
                    /* award-medal */   0x1f947, 0x1f948, 0x1f949, 0x1f3c6,
                    /* office */        0x1f4c6,
                    /* warning */       0x26a0, 0x26d4, 0x1f6ab, 0x1f6b3, 0x1f6d1, 0x2622,
                    /* av-symbol */     0x1f505, 0x1f506,
                    /* other-symbol */  0x2b55, 0x2705, 0x2611, 0x2714, 0x2716, 0x2795, 0x2796, 0x274c, 0x274e, 0x2733, 0x2734, 0x2747, 0x203c, 0x2049, 0x2753, 0x2757,
                    /* flags */         0x1f3c1, 0x1f6a9, 0x1f3f4, 0x1f3f3,
                    /* numbers */       NUMBER_START, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, NUMBER_END,
            }),
            // category custom symbols - will be filled dynamically below; has to be at position CUSTOM_GLYPHS_ID within EmojiSet[]
            new EmojiSet(CUSTOM_ICONS_START_CIRCLES + 18 + CUSTOM_SET_SIZE_PER_OPACITY, new int[CUSTOM_SET_SIZE_PER_OPACITY]),    // "18" to pick red circle instead of black
            // category places
            new EmojiSet(0x1f30d, new int[]{
                    /* globe */         0x1f30d, 0x1f30e, 0x1f30f, 0x1f5fa,
                    /* geographic */    0x26f0, 0x1f3d4, 0x1f3d6, 0x1f3dc, 0x1f3dd, 0x1f3de,
                    /* buildings */     0x1f3e0, 0x1f3e1, 0x1f3e2, 0x1f3d9, 0x1f3eb, 0x1f3ea, 0x1F3ed, 0x1f3e5, 0x1f3da, 0x1f3f0,
                    /* other */         0x1f5fd, 0x26f2, 0x2668, 0x1f6d2, 0x1f3ad, 0x1f3a8,
                    /* plants */        0x1f332, 0x1f333, 0x1f334, 0x1f335, 0x1f340,
                    /* transport */     0x1f682, 0x1f683, 0x1f686, 0x1f687, 0x1f68d, 0x1f695, 0x1f6b2, 0x1f697, 0x1f699, 0x2693, 0x26f5, 0x2708, 0x1f680,
                    /* transp.-sign */  0x267f, 0x1f6bb,
                    /* time */          0x23f3, 0x231a, 0x23f1, 0x1f324, 0x2600, 0x1f319, 0x1f318, SPARKLES
            }),
            // category food
            new EmojiSet(0x2615, new int[]{
                    /* fruits */        0x1f34a, 0x1f34b, 0x1f34d, 0x1f34e, 0x1f34f, 0x1f95d, 0x1f336, 0x1f344,
                    /* other */         0x1f968, 0x1f354, 0x1f355,
                    /* food-sweet */    0x1f366, 0x1f370, 0x1f36d,
                    /* drink */         0x1f964, 0x2615, 0x1f37a
            }),
            // category activity
            new EmojiSet(0x1f3c3, new int[]{
                    /* person-sport */  0x26f7, 0x1f3c4, 0x1f6a3, 0x1f3ca, 0x1f6b4,
                    /* p.-activity */   0x1f6b5, 0x1f9d7,
                    /* person-role */   0x1f575,
                    /* sport */         0x26bd, 0x1f94e, 0x1f3c0, 0x1f3c8, 0x1f93f, 0x1f3bf, 0x1f3af, 0x1f9ff,
                    /* tool */          0x1fa9c, 0x1f3a3, 0x1f6e0, 0x1fa9b, 0x1f512, 0x1f511, 0x1f50b, 0x1f9f2,
                    /* science */       0x2697, 0x1f9ea, 0x1f52c,
                    /* other things */  0x1f50e, 0x1f526, 0x1f4a1, 0x1f4d4, 0x1f4dc, 0x1f4ec, 0x1f3f7

            }),
            // category people
            new EmojiSet(0x1f600, new int[]{
                    /* smileys */       SMILEY_LIKE, SMILEY_LOVE, 0x1f641, 0x1f621, SMILEY_MONOCLE,
                    /* silhouettes */   0x1f47b, 0x1f464, 0x1f465, 0x1f5e3,<commit_msg>add two travel-related emojis<commit_after>package cgeo.geocaching.utils;

import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.R;
import cgeo.geocaching.databinding.DialogTitleButtonButtonBinding;
import cgeo.geocaching.databinding.EmojiselectorBinding;
import cgeo.geocaching.maps.CacheMarker;
import cgeo.geocaching.models.Geocache;
import cgeo.geocaching.storage.extension.EmojiLRU;
import cgeo.geocaching.storage.extension.OneTimeDialogs;
import cgeo.geocaching.ui.ViewUtils;
import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.functions.Action1;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.graphics.drawable.BitmapDrawable;
import android.os.Build;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.Pair;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import java.util.HashMap;
import java.util.Map;

import com.google.android.material.button.MaterialButton;
import org.apache.commons.lang3.builder.HashCodeBuilder;

public class EmojiUtils {

    public static final int NO_EMOJI = 0;

    // internal consts for calculated circles
    private static final int COLOR_VALUES = 3;  // supported # of different values per RGB
    private static final int COLOR_SPREAD = 127;
    private static final int COLOR_OFFSET = 0;
    private static final int OPACITY_VALUES = 5;
    private static final int OPACITY_SPREAD = 51;
    private static final int CUSTOM_SET_SIZE_PER_OPACITY = COLOR_VALUES * COLOR_VALUES * COLOR_VALUES;
    private static final int CUSTOM_SET_SIZE = CUSTOM_SET_SIZE_PER_OPACITY * OPACITY_VALUES;

    // internal consts for plain numbers
    private static final int NUMBER_START = 0x30;
    private static final int NUMBER_END = 0x39;

    // Unicode custom glyph area needed/supported by this class
    private static final int CUSTOM_ICONS_START = 0xe000;
    private static final int CUSTOM_ICONS_END = CUSTOM_ICONS_START + CUSTOM_SET_SIZE - 1; // max. possible value by Unicode definition: 0xf8ff;
    private static final int CUSTOM_ICONS_START_CIRCLES = CUSTOM_ICONS_START;

    // Select emoji variation for unicode characters, see https://emojipedia.org/variation-selector-16/
    private static final int VariationSelectorEmoji = 0xfe0f;

    // list of emojis supported by the EmojiPopup
    // should ideally be supported by the Android API level we have set as minimum (currently API 21 = Android 5),
    // but starting with API 23 (Android 6) the app automatically filters out characters not supported by their fonts
    // for a list of supported Unicode standards by API level see https://developer.android.com/guide/topics/resources/internationalization
    // for characters by Unicode version see https://unicode.org/emoji/charts-5.0/full-emoji-list.html (v5.0 - preferred compatibility standard based on our minAPI level)
    // The newest emoji standard can be found here: https://unicode.org/emoji/charts/full-emoji-list.html

    public static final int SMILEY_LIKE = 0x1f600;
    public static final int SMILEY_LOVE = 0x1f499;
    public static final int SMILEY_MONOCLE = 0x1f453;
    public static final int SPARKLES = 0x2728;


    private static final EmojiSet[] symbols = {
            // category symbols
            new EmojiSet(0x2764, new int[]{
                    /* hearts */        0x2764, 0x1f9e1, 0x1f49b, 0x1f49a, 0x1f499, 0x1f49c, 0x1f90e, 0x1f5a4, 0x1f90d,
                    /* geometric */     0x1f7e5, 0x1f7e7, 0x1f7e8, 0x1f7e9, 0x1f7e6, 0x1f7ea, 0x1f7eb, 0x2b1b, 0x2b1c,
                    /* geometric */     0x1f536, 0x1f537,
                    /* events */        0x1f383, 0x1f380, 0x1f384, 0x1f389,
                    /* award-medal */   0x1f947, 0x1f948, 0x1f949, 0x1f3c6,
                    /* office */        0x1f4c6,
                    /* warning */       0x26a0, 0x26d4, 0x1f6ab, 0x1f6b3, 0x1f6d1, 0x2622,
                    /* av-symbol */     0x1f505, 0x1f506,
                    /* other-symbol */  0x2b55, 0x2705, 0x2611, 0x2714, 0x2716, 0x2795, 0x2796, 0x274c, 0x274e, 0x2733, 0x2734, 0x2747, 0x203c, 0x2049, 0x2753, 0x2757,
                    /* flags */         0x1f3c1, 0x1f6a9, 0x1f3f4, 0x1f3f3,
                    /* numbers */       NUMBER_START, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, NUMBER_END,
            }),
            // category custom symbols - will be filled dynamically below; has to be at position CUSTOM_GLYPHS_ID within EmojiSet[]
            new EmojiSet(CUSTOM_ICONS_START_CIRCLES + 18 + CUSTOM_SET_SIZE_PER_OPACITY, new int[CUSTOM_SET_SIZE_PER_OPACITY]),    // "18" to pick red circle instead of black
            // category places
            new EmojiSet(0x1f30d, new int[]{
                    /* globe */         0x1f30d, 0x1f30e, 0x1f30f, 0x1f5fa,
                    /* geographic */    0x26f0, 0x1f3d4, 0x1f3d6, 0x1f3dc, 0x1f3dd, 0x1f3de,
                    /* buildings */     0x1f3e0, 0x1f3e1, 0x1f3e2, 0x1f3d9, 0x1f3eb, 0x1f3ea, 0x1F3ed, 0x1f3e5, 0x1f3da, 0x1f3f0,
                    /* other */         0x1f5fd, 0x26f2, 0x2668, 0x1f6d2, 0x1f3ad, 0x1f3a8,
                    /* plants */        0x1f332, 0x1f333, 0x1f334, 0x1f335, 0x1f340,
                    /* transport */     0x1f682, 0x1f683, 0x1f686, 0x1f687, 0x1f68d, 0x1f695, 0x1f6b2, 0x1f697, 0x1f699, 0x26fd, 0x1f6a7, 0x2693, 0x26f5, 0x2708, 0x1f680,
                    /* transp.-sign */  0x267f, 0x1f6bb,
                    /* time */          0x23f3, 0x231a, 0x23f1, 0x1f324, 0x2600, 0x1f319, 0x1f318, SPARKLES
            }),
            // category food
            new EmojiSet(0x2615, new int[]{
                    /* fruits */        0x1f34a, 0x1f34b, 0x1f34d, 0x1f34e, 0x1f34f, 0x1f95d, 0x1f336, 0x1f344,
                    /* other */         0x1f968, 0x1f354, 0x1f355,
                    /* food-sweet */    0x1f366, 0x1f370, 0x1f36d,
                    /* drink */         0x1f964, 0x2615, 0x1f37a
            }),
            // category activity
            new EmojiSet(0x1f3c3, new int[]{
                    /* person-sport */  0x26f7, 0x1f3c4, 0x1f6a3, 0x1f3ca, 0x1f6b4,
                    /* p.-activity */   0x1f6b5, 0x1f9d7,
                    /* person-role */   0x1f575,
                    /* sport */         0x26bd, 0x1f94e, 0x1f3c0, 0x1f3c8, 0x1f93f, 0x1f3bf, 0x1f3af, 0x1f9ff,
                    /* tool */          0x1fa9c, 0x1f3a3, 0x1f6e0, 0x1fa9b, 0x1f512, 0x1f511, 0x1f50b, 0x1f9f2,
                    /* science */       0x2697, 0x1f9ea, 0x1f52c,
                    /* other things */  0x1f50e, 0x1f526, 0x1f4a1, 0x1f4d4, 0x1f4dc, 0x1f4ec, 0x1f3f7

            }),
            // category people
            new EmojiSet(0x1f600, new int[]{
                    /* smileys */       SMILEY_LIKE, SMILEY_LOVE, 0x1f641, 0x1f621, SMILEY_MONOCLE,
                    /* silhouettes */   0x1f47b, 0x1f464, 0x1f465, 0x1f5e3,
{'fraction_non_alphanumeric': 0.08849139385757678, 'fraction_numerical': 0.11049611879851502, 'mean_word_length': 2.5200760275599907, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 8, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4546633', 'n_tokens_mistral': 6354, 'n_tokens_neox': 5482, 'n_words': 1194}