From 94085798621f4036454fef2a4096ad7588a80793 Mon Sep 17 00:00:00 2001 From: Jake McGinty Date: Thu, 21 May 2015 17:29:23 -0700 Subject: [PATCH] ASCII emoji support Fixes #2943 Closes #3283 // FREEBIE --- assets/{emoji-2.png => emoji-nature.png} | Bin assets/{emoji-1.png => emoji-objects.png} | Bin assets/{emoji-0.png => emoji-people.png} | Bin assets/{emoji-3.png => emoji-places.png} | Bin assets/{emoji-4.png => emoji-symbol.png} | Bin res/drawable/emoji_category_emoticons.xml | 8 + res/values/emoji.xml | 887 ------------------ .../components/emoji/EmojiDrawer.java | 19 +- .../components/emoji/EmojiEditText.java | 9 +- .../components/emoji/EmojiPageModel.java | 4 +- .../components/emoji/EmojiPageView.java | 30 +- .../components/emoji/EmojiPages.java | 164 ++++ .../components/emoji/EmojiProvider.java | 40 +- .../securesms/components/emoji/EmojiView.java | 79 ++ .../emoji/RecentEmojiPageModel.java | 67 +- .../emoji/StaticEmojiPageModel.java | 25 +- 16 files changed, 341 insertions(+), 991 deletions(-) rename assets/{emoji-2.png => emoji-nature.png} (100%) rename assets/{emoji-1.png => emoji-objects.png} (100%) rename assets/{emoji-0.png => emoji-people.png} (100%) rename assets/{emoji-3.png => emoji-places.png} (100%) rename assets/{emoji-4.png => emoji-symbol.png} (100%) create mode 100644 res/drawable/emoji_category_emoticons.xml create mode 100644 src/org/thoughtcrime/securesms/components/emoji/EmojiPages.java create mode 100644 src/org/thoughtcrime/securesms/components/emoji/EmojiView.java diff --git a/assets/emoji-2.png b/assets/emoji-nature.png similarity index 100% rename from assets/emoji-2.png rename to assets/emoji-nature.png diff --git a/assets/emoji-1.png b/assets/emoji-objects.png similarity index 100% rename from assets/emoji-1.png rename to assets/emoji-objects.png diff --git a/assets/emoji-0.png b/assets/emoji-people.png similarity index 100% rename from assets/emoji-0.png rename to assets/emoji-people.png diff --git a/assets/emoji-3.png b/assets/emoji-places.png similarity index 100% rename from assets/emoji-3.png rename to assets/emoji-places.png diff --git a/assets/emoji-4.png b/assets/emoji-symbol.png similarity index 100% rename from assets/emoji-4.png rename to assets/emoji-symbol.png diff --git a/res/drawable/emoji_category_emoticons.xml b/res/drawable/emoji_category_emoticons.xml new file mode 100644 index 0000000000..8777fb389a --- /dev/null +++ b/res/drawable/emoji_category_emoticons.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/res/values/emoji.xml b/res/values/emoji.xml index 1aaf0942fa..045e125f3d 100644 --- a/res/values/emoji.xml +++ b/res/values/emoji.xml @@ -1,890 +1,3 @@ - - 0x1f415 - 0x1f436 - 0x1f429 - 0x1f408 - 0x1f431 - 0x1f400 - 0x1f401 - 0x1f42d - 0x1f439 - 0x1f422 - 0x1f407 - 0x1f430 - 0x1f413 - 0x1f414 - 0x1f423 - 0x1f424 - 0x1f425 - 0x1f426 - 0x1f40f - 0x1f411 - 0x1f410 - 0x1f43a - 0x1f403 - 0x1f402 - 0x1f404 - 0x1f42e - 0x1f434 - 0x1f417 - 0x1f416 - 0x1f437 - 0x1f43d - 0x1f438 - 0x1f40d - 0x1f43c - 0x1f427 - 0x1f418 - 0x1f428 - 0x1f412 - 0x1f435 - 0x1f406 - 0x1f42f - 0x1f43b - 0x1f42b - 0x1f42a - 0x1f40a - 0x1f433 - 0x1f40b - 0x1f41f - 0x1f420 - 0x1f421 - 0x1f419 - 0x1f41a - 0x1f42c - 0x1f40c - 0x1f41b - 0x1f41c - 0x1f41d - 0x1f41e - 0x1f432 - 0x1f409 - 0x1f43e - 0x1f378 - 0x1f37a - 0x1f37b - 0x1f377 - 0x1f379 - 0x1f376 - 0x2615 - 0x1f375 - 0x1f37c - 0x1f374 - 0x1f368 - 0x1f367 - 0x1f366 - 0x1f369 - 0x1f370 - 0x1f36a - 0x1f36b - 0x1f36c - 0x1f36d - 0x1f36e - 0x1f36f - 0x1f373 - 0x1f354 - 0x1f35f - 0x1f35d - 0x1f355 - 0x1f356 - 0x1f357 - 0x1f364 - 0x1f363 - 0x1f371 - 0x1f35e - 0x1f35c - 0x1f359 - 0x1f35a - 0x1f35b - 0x1f372 - 0x1f365 - 0x1f362 - 0x1f361 - 0x1f358 - 0x1f360 - 0x1f34c - 0x1f34e - 0x1f34f - 0x1f34a - 0x1f34b - 0x1f344 - 0x1f345 - 0x1f346 - 0x1f347 - 0x1f348 - 0x1f349 - 0x1f350 - 0x1f351 - 0x1f352 - 0x1f353 - 0x1f34d - 0x1f330 - 0x1f331 - 0x1f332 - 0x1f333 - 0x1f334 - 0x1f335 - 0x1f337 - 0x1f338 - 0x1f339 - 0x1f340 - 0x1f341 - 0x1f342 - 0x1f343 - 0x1f33a - 0x1f33b - 0x1f33c - 0x1f33d - 0x1f33e - 0x1f33f - 0x2600 - 0x1f308 - 0x26c5 - 0x2601 - 0x1f301 - 0x1f302 - 0x2614 - 0x1f4a7 - 0x26a1 - 0x1f300 - 0x2744 - 0x26c4 - 0x1f319 - 0x1f31e - 0x1f31d - 0x1f31a - 0x1f31b - 0x1f31c - 0x1f311 - 0x1f312 - 0x1f313 - 0x1f314 - 0x1f315 - 0x1f316 - 0x1f317 - 0x1f318 - 0x1f391 - 0x1f304 - 0x1f305 - 0x1f307 - 0x1f306 - 0x1f303 - 0x1f30c - 0x1f309 - 0x1f30a - 0x1f30b - 0x1f30e - 0x1f30f - 0x1f30d - 0x1f310 - - - - 0x1f51d - 0x1f519 - 0x1f51b - 0x1f51c - 0x1f51a - 0x23f3 - 0x231b - 0x23f0 - 0x2648 - 0x2649 - 0x264a - 0x264b - 0x264c - 0x264d - 0x264e - 0x264f - 0x2650 - 0x2651 - 0x2652 - 0x2653 - 0x26ce - 0x1f531 - 0x1f52f - 0x1f6bb - 0x1f6ae - 0x1f6af - 0x1f6b0 - 0x1f6b1 - 0x1f170 - 0x1f171 - 0x1f18e - 0x1f17e - 0x1f4ae - 0x1f4af - 0x1f520 - 0x1f521 - 0x1f522 - 0x1f523 - 0x1f524 - 0x27bf - 0x1f4f6 - 0x1f4f3 - 0x1f4f4 - 0x1f4f5 - 0x1f6b9 - 0x1f6ba - 0x1f6bc - 0x267f - 0x267b - 0x1f6ad - 0x1f6a9 - 0x26a0 - 0x1f201 - 0x1f51e - 0x26d4 - 0x1f192 - 0x1f197 - 0x1f195 - 0x1f198 - 0x1f199 - 0x1f193 - 0x1f196 - 0x1f19a - 0x1f232 - 0x1f233 - 0x1f234 - 0x1f235 - 0x1f236 - 0x1f237 - 0x1f238 - 0x1f239 - 0x1f202 - 0x1f23a - 0x1f250 - 0x1f251 - 0x3299 - 0x00ae - 0x00a9 - 0x2122 - 0x1f21a - 0x1f22f - 0x3297 - 0x2b55 - 0x274c - 0x274e - 0x2139 - 0x1f6ab - 0x2705 - 0x2714 - 0x1f517 - 0x2734 - 0x2733 - 0x2795 - 0x2796 - 0x2716 - 0x2797 - 0x1f4a0 - 0x1f4a1 - 0x1f4a4 - 0x1f4a2 - 0x1f525 - 0x1f4a5 - 0x1f4a8 - 0x1f4a6 - 0x1f4ab - 0x1f55b - 0x1f567 - 0x1f550 - 0x1f55c - 0x1f551 - 0x1f55d - 0x1f552 - 0x1f55e - 0x1f553 - 0x1f55f - 0x1f554 - 0x1f560 - 0x1f555 - 0x1f561 - 0x1f556 - 0x1f562 - 0x1f557 - 0x1f563 - 0x1f558 - 0x1f564 - 0x1f559 - 0x1f565 - 0x1f55a - 0x1f566 - 0x2195 - 0x2b06 - 0x2197 - 0x27a1 - 0x2198 - 0x2b07 - 0x2199 - 0x2b05 - 0x2196 - 0x2194 - 0x2934 - 0x2935 - 0x23ea - 0x23eb - 0x23ec - 0x23e9 - 0x25c0 - 0x25b6 - 0x1f53d - 0x1f53c - 0x2747 - 0x2728 - 0x1f534 - 0x1f535 - 0x26aa - 0x26ab - 0x1f533 - 0x1f532 - 0x2b50 - 0x1f31f - 0x1f320 - 0x25ab - 0x25aa - 0x25fd - 0x25fe - 0x25fb - 0x25fc - 0x2b1c - 0x2b1b - 0x1f538 - 0x1f539 - 0x1f536 - 0x1f537 - 0x1f53a - 0x1f53b - 0x2754 - 0x2753 - 0x2755 - 0x2757 - 0x203c - 0x2049 - 0x3030 - 0x27b0 - 0x2660 - 0x2665 - 0x2663 - 0x2666 - 0x1f194 - 0x1f511 - 0x21a9 - 0x1f191 - 0x1f50d - 0x1f512 - 0x1f513 - 0x21aa - 0x1f510 - 0x2611 - 0x1f518 - 0x1f50e - 0x1f516 - 0x1f50f - 0x1f503 - 0x1f500 - 0x1f501 - 0x1f502 - 0x1f504 - 0x1f4e7 - 0x1f505 - 0x1f506 - 0x1f507 - 0x1f508 - 0x1f509 - 0x1f50a - - - 0x263a - 0x1f60a - 0x1f600 - 0x1f601 - 0x1f602 - 0x1f603 - 0x1f604 - 0x1f605 - 0x1f606 - 0x1f607 - 0x1f608 - 0x1f609 - 0x1f62f - 0x1f610 - 0x1f611 - 0x1f615 - 0x1f620 - 0x1f62c - 0x1f621 - 0x1f622 - 0x1f634 - 0x1f62e - 0x1f623 - 0x1f624 - 0x1f625 - 0x1f626 - 0x1f627 - 0x1f628 - 0x1f629 - 0x1f630 - 0x1f61f - 0x1f631 - 0x1f632 - 0x1f633 - 0x1f635 - 0x1f636 - 0x1f637 - 0x1f61e - 0x1f612 - 0x1f60d - 0x1f61b - 0x1f61c - 0x1f61d - 0x1f60b - 0x1f617 - 0x1f619 - 0x1f618 - 0x1f61a - 0x1f60e - 0x1f62d - 0x1f60c - 0x1f616 - 0x1f614 - 0x1f62a - 0x1f60f - 0x1f613 - 0x1f62b - 0x1f64b - 0x1f64c - 0x1f64d - 0x1f645 - 0x1f646 - 0x1f647 - 0x1f64e - 0x1f64f - 0x1f63a - 0x1f63c - 0x1f638 - 0x1f639 - 0x1f63b - 0x1f63d - 0x1f63f - 0x1f63e - 0x1f640 - 0x1f648 - 0x1f649 - 0x1f64a - 0x1f4a9 - 0x1f476 - 0x1f466 - 0x1f467 - 0x1f468 - 0x1f469 - 0x1f474 - 0x1f475 - 0x1f48f - 0x1f491 - 0x1f46a - 0x1f46b - 0x1f46c - 0x1f46d - 0x1f464 - 0x1f465 - 0x1f46e - 0x1f477 - 0x1f481 - 0x1f482 - 0x1f46f - 0x1f470 - 0x1f478 - 0x1f385 - 0x1f47c - 0x1f471 - 0x1f472 - 0x1f473 - 0x1f483 - 0x1f486 - 0x1f487 - 0x1f485 - 0x1f47b - 0x1f479 - 0x1f47a - 0x1f47d - 0x1f47e - 0x1f47f - 0x1f480 - 0x1f4aa - 0x1f440 - 0x1f442 - 0x1f443 - 0x1f463 - 0x1f444 - 0x1f445 - 0x1f48b - 0x2764 - 0x1f499 - 0x1f49a - 0x1f49b - 0x1f49c - 0x1f493 - 0x1f494 - 0x1f495 - 0x1f496 - 0x1f497 - 0x1f498 - 0x1f49d - 0x1f49e - 0x1f49f - 0x1f44d - 0x1f44e - 0x1f44c - 0x270a - 0x270c - 0x270b - 0x1f44a - 0x261d - 0x1f446 - 0x1f447 - 0x1f448 - 0x1f449 - 0x1f44b - 0x1f44f - 0x1f450 - - - 0x1f530 - 0x1f484 - 0x1f45e - 0x1f45f - 0x1f451 - 0x1f452 - 0x1f3a9 - 0x1f393 - 0x1f453 - 0x231a - 0x1f454 - 0x1f455 - 0x1f456 - 0x1f457 - 0x1f458 - 0x1f459 - 0x1f460 - 0x1f461 - 0x1f462 - 0x1f45a - 0x1f45c - 0x1f4bc - 0x1f392 - 0x1f45d - 0x1f45b - 0x1f4b0 - 0x1f4b3 - 0x1f4b2 - 0x1f4b5 - 0x1f4b4 - 0x1f4b6 - 0x1f4b7 - 0x1f4b8 - 0x1f4b1 - 0x1f4b9 - 0x1f52b - 0x1f52a - 0x1f4a3 - 0x1f489 - 0x1f48a - 0x1f6ac - 0x1f514 - 0x1f515 - 0x1f6aa - 0x1f52c - 0x1f52d - 0x1f52e - 0x1f526 - 0x1f50b - 0x1f50c - 0x1f4dc - 0x1f4d7 - 0x1f4d8 - 0x1f4d9 - 0x1f4da - 0x1f4d4 - 0x1f4d2 - 0x1f4d1 - 0x1f4d3 - 0x1f4d5 - 0x1f4d6 - 0x1f4f0 - 0x1f4db - 0x1f383 - 0x1f384 - 0x1f380 - 0x1f381 - 0x1f382 - 0x1f388 - 0x1f386 - 0x1f387 - 0x1f389 - 0x1f38a - 0x1f38d - 0x1f38f - 0x1f38c - 0x1f390 - 0x1f38b - 0x1f38e - 0x1f4f1 - 0x1f4f2 - 0x1f4df - 0x260e - 0x1f4de - 0x1f4e0 - 0x1f4e6 - 0x2709 - 0x1f4e8 - 0x1f4e9 - 0x1f4ea - 0x1f4eb - 0x1f4ed - 0x1f4ec - 0x1f4ee - 0x1f4e4 - 0x1f4e5 - 0x1f4ef - 0x1f4e2 - 0x1f4e3 - 0x1f4e1 - 0x1f4ac - 0x1f4ad - 0x2712 - 0x270f - 0x1f4dd - 0x1f4cf - 0x1f4d0 - 0x1f4cd - 0x1f4cc - 0x1f4ce - 0x2702 - 0x1f4ba - 0x1f4bb - 0x1f4bd - 0x1f4be - 0x1f4bf - 0x1f4c6 - 0x1f4c5 - 0x1f4c7 - 0x1f4cb - 0x1f4c1 - 0x1f4c2 - 0x1f4c3 - 0x1f4c4 - 0x1f4ca - 0x1f4c8 - 0x1f4c9 - 0x26fa - 0x1f3a1 - 0x1f3a2 - 0x1f3a0 - 0x1f3aa - 0x1f3a8 - 0x1f3ac - 0x1f3a5 - 0x1f4f7 - 0x1f4f9 - 0x1f3a6 - 0x1f3ad - 0x1f3ab - 0x1f3ae - 0x1f3b2 - 0x1f3b0 - 0x1f0cf - 0x1f3b4 - 0x1f004 - 0x1f3af - 0x1f4fa - 0x1f4fb - 0x1f4c0 - 0x1f4fc - 0x1f3a7 - 0x1f3a4 - 0x1f3b5 - 0x1f3b6 - 0x1f3bc - 0x1f3bb - 0x1f3b9 - 0x1f3b7 - 0x1f3ba - 0x1f3b8 - 0x303d - - - 0x1f3e0 - 0x1f3e1 - 0x1f3e2 - 0x1f3e3 - 0x1f3e4 - 0x1f3e5 - 0x1f3e6 - 0x1f3e7 - 0x1f3e8 - 0x1f3e9 - 0x1f3ea - 0x1f3eb - 0x26ea - 0x26f2 - 0x1f3ec - 0x1f3ef - 0x1f3f0 - 0x1f3ed - 0x1f5fb - 0x1f5fc - 0x1f5fd - 0x1f5fe - 0x1f5ff - 0x2693 - 0x1f3ee - 0x1f488 - 0x1f527 - 0x1f528 - 0x1f529 - 0x1f6bf - 0x1f6c1 - 0x1f6c0 - 0x1f6bd - 0x1f6be - 0x1f3bd - 0x1f3a3 - 0x1f3b1 - 0x1f3b3 - 0x26be - 0x26f3 - 0x1f3be - 0x26bd - 0x1f3bf - 0x1f3c0 - 0x1f3c1 - 0x1f3c2 - 0x1f3c3 - 0x1f3c4 - 0x1f3c6 - 0x1f3c7 - 0x1f40e - 0x1f3c8 - 0x1f3c9 - 0x1f3ca - 0x1f682 - 0x1f683 - 0x1f684 - 0x1f685 - 0x1f686 - 0x1f687 - 0x24c2 - 0x1f688 - 0x1f68a - 0x1f68b - 0x1f68c - 0x1f68d - 0x1f68e - 0x1f68f - 0x1f690 - 0x1f691 - 0x1f692 - 0x1f693 - 0x1f694 - 0x1f695 - 0x1f696 - 0x1f697 - 0x1f698 - 0x1f699 - 0x1f69a - 0x1f69b - 0x1f69c - 0x1f69d - 0x1f69e - 0x1f69f - 0x1f6a0 - 0x1f6a1 - 0x1f6a2 - 0x1f6a3 - 0x1f681 - 0x2708 - 0x1f6c2 - 0x1f6c3 - 0x1f6c4 - 0x1f6c5 - 0x26f5 - 0x1f6b2 - 0x1f6b3 - 0x1f6b4 - 0x1f6b5 - 0x1f6b7 - 0x1f6b8 - 0x1f689 - 0x1f680 - 0x1f6a4 - 0x1f6b6 - 0x26fd - 0x1f17f - 0x1f6a5 - 0x1f6a6 - 0x1f6a7 - 0x1f6a8 - 0x2668 - 0x1f48c - 0x1f48d - 0x1f48e - 0x1f490 - 0x1f492 - - - - =-O - :-P - ;-) - :-( - :-) - :-! - :-$ - B-) - :O - :-* - :-D - ":'(" - :-\\ - O:-) - :-[ - - - - @array/emoji_people - @array/emoji_objects - @array/emoji_nature - @array/emoji_places - @array/emoji_symbols - - - - @drawable/emoji_category_people - @drawable/emoji_category_objects - @drawable/emoji_category_nature - @drawable/emoji_category_places - @drawable/emoji_category_symbol - diff --git a/src/org/thoughtcrime/securesms/components/emoji/EmojiDrawer.java b/src/org/thoughtcrime/securesms/components/emoji/EmojiDrawer.java index 07105bd40d..7719b480b1 100644 --- a/src/org/thoughtcrime/securesms/components/emoji/EmojiDrawer.java +++ b/src/org/thoughtcrime/securesms/components/emoji/EmojiDrawer.java @@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.components.emoji; import android.content.Context; import android.support.annotation.ArrayRes; +import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.view.PagerAdapter; @@ -62,7 +63,7 @@ public class EmojiDrawer extends KeyboardAwareLinearLayout { private void init() { final View v = LayoutInflater.from(getContext()).inflate(R.layout.emoji_drawer, this, true); initializeResources(v); - initializePageModels(R.array.emoji_categories, R.array.emoji_category_icons); + initializePageModels(); initializeEmojiGrid(); } @@ -102,27 +103,23 @@ public class EmojiDrawer extends KeyboardAwareLinearLayout { pager.setAdapter(new EmojiPagerAdapter(getContext(), models, new EmojiSelectionListener() { - @Override public void onEmojiSelected(int emojiCode) { - recentModel.onCodePointSelected(emojiCode); - composeText.insertEmoji(emojiCode); + @Override public void onEmojiSelected(String emoji) { + recentModel.onCodePointSelected(emoji); + composeText.insertEmoji(emoji); } })); - if (recentModel.getCodePoints().length == 0) { + if (recentModel.getEmoji().length == 0) { pager.setCurrentItem(1); } strip.setViewPager(pager); } - private void initializePageModels(@ArrayRes int pagesRes, @ArrayRes int iconsRes) { - final int[] icons = ResUtil.getResourceIds(getContext(), iconsRes); - final int[] pages = ResUtil.getResourceIds(getContext(), pagesRes); + private void initializePageModels() { this.models = new LinkedList<>(); this.recentModel = new RecentEmojiPageModel(getContext()); this.models.add(recentModel); - for (int i = 0; i < icons.length; i++) { - this.models.add(new StaticEmojiPageModel(icons[i], getResources().getIntArray(pages[i]))); - } + this.models.addAll(EmojiPages.PAGES); } public static class EmojiPagerAdapter extends PagerAdapter diff --git a/src/org/thoughtcrime/securesms/components/emoji/EmojiEditText.java b/src/org/thoughtcrime/securesms/components/emoji/EmojiEditText.java index 5ee4680dde..ccffb2dfd2 100644 --- a/src/org/thoughtcrime/securesms/components/emoji/EmojiEditText.java +++ b/src/org/thoughtcrime/securesms/components/emoji/EmojiEditText.java @@ -22,19 +22,18 @@ public class EmojiEditText extends AppCompatEditText { } @Override public void setText(CharSequence text, BufferType type) { - super.setText(EmojiProvider.getInstance(getContext()).emojify(text, EmojiProvider.EMOJI_SMALL, new PostInvalidateCallback(this)), + super.setText(EmojiProvider.getInstance(getContext()).emojify(text, EmojiProvider.EMOJI_SMALL, callback), BufferType.SPANNABLE); } - public void insertEmoji(int codePoint) { + public void insertEmoji(String emoji) { final int start = getSelectionStart(); final int end = getSelectionEnd(); - final char[] chars = Character.toChars(codePoint); - final CharSequence text = EmojiProvider.getInstance(getContext()).emojify(new String(chars), + final CharSequence text = EmojiProvider.getInstance(getContext()).emojify(emoji, EmojiProvider.EMOJI_SMALL, callback); getText().replace(Math.min(start, end), Math.max(start, end), text); - setSelection(end + chars.length); + setSelection(end + emoji.length()); } } diff --git a/src/org/thoughtcrime/securesms/components/emoji/EmojiPageModel.java b/src/org/thoughtcrime/securesms/components/emoji/EmojiPageModel.java index 4ddcee5c20..ead5ada69e 100644 --- a/src/org/thoughtcrime/securesms/components/emoji/EmojiPageModel.java +++ b/src/org/thoughtcrime/securesms/components/emoji/EmojiPageModel.java @@ -2,6 +2,8 @@ package org.thoughtcrime.securesms.components.emoji; public interface EmojiPageModel { int getIconRes(); - int[] getCodePoints(); + String[] getEmoji(); + boolean hasSpriteMap(); + String getSprite(); boolean isDynamic(); } diff --git a/src/org/thoughtcrime/securesms/components/emoji/EmojiPageView.java b/src/org/thoughtcrime/securesms/components/emoji/EmojiPageView.java index a2c0532509..1147c63a77 100644 --- a/src/org/thoughtcrime/securesms/components/emoji/EmojiPageView.java +++ b/src/org/thoughtcrime/securesms/components/emoji/EmojiPageView.java @@ -14,7 +14,6 @@ import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; import android.widget.FrameLayout; import android.widget.GridView; -import android.widget.ImageView; import org.thoughtcrime.securesms.R; @@ -58,7 +57,7 @@ public class EmojiPageView extends FrameLayout { grid.setColumnWidth(getResources().getDimensionPixelSize(R.dimen.emoji_drawer_size) + 2 * getResources().getDimensionPixelSize(R.dimen.emoji_drawer_item_padding)); grid.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { - if (listener != null) listener.onEmojiSelected((Integer)view.getTag()); + if (listener != null) listener.onEmojiSelected((String)view.getTag()); } }); } @@ -85,7 +84,7 @@ public class EmojiPageView extends FrameLayout { } @Override public int getCount() { - return model.getCodePoints().length; + return model.getEmoji().length; } @Override @@ -100,29 +99,24 @@ public class EmojiPageView extends FrameLayout { @Override public View getView(final int position, final View convertView, final ViewGroup parent) { - final ImageView view; + final EmojiView view; final int pad = context.getResources().getDimensionPixelSize(R.dimen.emoji_drawer_item_padding); - if (convertView != null && convertView instanceof ImageView) { - view = (ImageView)convertView; + if (convertView != null && convertView instanceof EmojiView) { + view = (EmojiView)convertView; } else { - ImageView imageView = new ImageView(context); - imageView.setPadding(pad, pad, pad, pad); - imageView.setLayoutParams(new AbsListView.LayoutParams(emojiSize + 2 * pad, emojiSize + 2 * pad)); - view = imageView; + EmojiView emojiView = new EmojiView(context); + emojiView.setPadding(pad, pad, pad, pad); + emojiView.setLayoutParams(new AbsListView.LayoutParams(emojiSize + 2 * pad, emojiSize + 2 * pad)); + view = emojiView; } - final Integer unicodeTag = model.getCodePoints()[position]; - final EmojiProvider provider = EmojiProvider.getInstance(context); - final Drawable drawable = provider.getEmojiDrawable(unicodeTag, EmojiProvider.EMOJI_FULL); - - view.setImageDrawable(drawable); - view.setPadding(pad, pad, pad, pad); - view.setTag(unicodeTag); + view.setEmoji(model.getEmoji()[position]); + view.setTag(model.getEmoji()[position]); return view; } } public interface EmojiSelectionListener { - void onEmojiSelected(int emojiCode); + void onEmojiSelected(String emoji); } } diff --git a/src/org/thoughtcrime/securesms/components/emoji/EmojiPages.java b/src/org/thoughtcrime/securesms/components/emoji/EmojiPages.java new file mode 100644 index 0000000000..dfc1064d47 --- /dev/null +++ b/src/org/thoughtcrime/securesms/components/emoji/EmojiPages.java @@ -0,0 +1,164 @@ +package org.thoughtcrime.securesms.components.emoji; + +import org.thoughtcrime.securesms.R; + +import java.util.Arrays; +import java.util.List; + +public class EmojiPages { + public static final List PAGES = Arrays.asList( + new StaticEmojiPageModel(R.drawable.emoji_category_people, new String[] { + "\u263a", "\ud83d\ude0a", "\ud83d\ude00", "\ud83d\ude01", "\ud83d\ude02", "\ud83d\ude03", + "\ud83d\ude04", "\ud83d\ude05", "\ud83d\ude06", "\ud83d\ude07", "\ud83d\ude08", "\ud83d\ude09", + "\ud83d\ude2f", "\ud83d\ude10", "\ud83d\ude11", "\ud83d\ude15", "\ud83d\ude20", "\ud83d\ude2c", + "\ud83d\ude21", "\ud83d\ude22", "\ud83d\ude34", "\ud83d\ude2e", "\ud83d\ude23", "\ud83d\ude24", + "\ud83d\ude25", "\ud83d\ude26", "\ud83d\ude27", "\ud83d\ude28", "\ud83d\ude29", "\ud83d\ude30", + "\ud83d\ude1f", "\ud83d\ude31", "\ud83d\ude32", "\ud83d\ude33", "\ud83d\ude35", "\ud83d\ude36", + "\ud83d\ude37", "\ud83d\ude1e", "\ud83d\ude12", "\ud83d\ude0d", "\ud83d\ude1b", "\ud83d\ude1c", + "\ud83d\ude1d", "\ud83d\ude0b", "\ud83d\ude17", "\ud83d\ude19", "\ud83d\ude18", "\ud83d\ude1a", + "\ud83d\ude0e", "\ud83d\ude2d", "\ud83d\ude0c", "\ud83d\ude16", "\ud83d\ude14", "\ud83d\ude2a", + "\ud83d\ude0f", "\ud83d\ude13", "\ud83d\ude2b", "\ud83d\ude4b", "\ud83d\ude4c", "\ud83d\ude4d", + "\ud83d\ude45", "\ud83d\ude46", "\ud83d\ude47", "\ud83d\ude4e", "\ud83d\ude4f", "\ud83d\ude3a", + "\ud83d\ude3c", "\ud83d\ude38", "\ud83d\ude39", "\ud83d\ude3b", "\ud83d\ude3d", "\ud83d\ude3f", + "\ud83d\ude3e", "\ud83d\ude40", "\ud83d\ude48", "\ud83d\ude49", "\ud83d\ude4a", "\ud83d\udca9", + "\ud83d\udc76", "\ud83d\udc66", "\ud83d\udc67", "\ud83d\udc68", "\ud83d\udc69", "\ud83d\udc74", + "\ud83d\udc75", "\ud83d\udc8f", "\ud83d\udc91", "\ud83d\udc6a", "\ud83d\udc6b", "\ud83d\udc6c", + "\ud83d\udc6d", "\ud83d\udc64", "\ud83d\udc65", "\ud83d\udc6e", "\ud83d\udc77", "\ud83d\udc81", + "\ud83d\udc82", "\ud83d\udc6f", "\ud83d\udc70", "\ud83d\udc78", "\ud83c\udf85", "\ud83d\udc7c", + "\ud83d\udc71", "\ud83d\udc72", "\ud83d\udc73", "\ud83d\udc83", "\ud83d\udc86", "\ud83d\udc87", + "\ud83d\udc85", "\ud83d\udc7b", "\ud83d\udc79", "\ud83d\udc7a", "\ud83d\udc7d", "\ud83d\udc7e", + "\ud83d\udc7f", "\ud83d\udc80", "\ud83d\udcaa", "\ud83d\udc40", "\ud83d\udc42", "\ud83d\udc43", + "\ud83d\udc63", "\ud83d\udc44", "\ud83d\udc45", "\ud83d\udc8b", "\u2764", "\ud83d\udc99", + "\ud83d\udc9a", "\ud83d\udc9b", "\ud83d\udc9c", "\ud83d\udc93", "\ud83d\udc94", "\ud83d\udc95", + "\ud83d\udc96", "\ud83d\udc97", "\ud83d\udc98", "\ud83d\udc9d", "\ud83d\udc9e", "\ud83d\udc9f", + "\ud83d\udc4d", "\ud83d\udc4e", "\ud83d\udc4c", "\u270a", "\u270c", "\u270b", + "\ud83d\udc4a", "\u261d", "\ud83d\udc46", "\ud83d\udc47", "\ud83d\udc48", "\ud83d\udc49", + "\ud83d\udc4b", "\ud83d\udc4f", "\ud83d\udc50", + }, "emoji-people.png"), + new StaticEmojiPageModel(R.drawable.emoji_category_objects, new String[] { + "\ud83d\udd30", "\ud83d\udc84", "\ud83d\udc5e", "\ud83d\udc5f", "\ud83d\udc51", "\ud83d\udc52", + "\ud83c\udfa9", "\ud83c\udf93", "\ud83d\udc53", "\u231a", "\ud83d\udc54", "\ud83d\udc55", + "\ud83d\udc56", "\ud83d\udc57", "\ud83d\udc58", "\ud83d\udc59", "\ud83d\udc60", "\ud83d\udc61", + "\ud83d\udc62", "\ud83d\udc5a", "\ud83d\udc5c", "\ud83d\udcbc", "\ud83c\udf92", "\ud83d\udc5d", + "\ud83d\udc5b", "\ud83d\udcb0", "\ud83d\udcb3", "\ud83d\udcb2", "\ud83d\udcb5", "\ud83d\udcb4", + "\ud83d\udcb6", "\ud83d\udcb7", "\ud83d\udcb8", "\ud83d\udcb1", "\ud83d\udcb9", "\ud83d\udd2b", + "\ud83d\udd2a", "\ud83d\udca3", "\ud83d\udc89", "\ud83d\udc8a", "\ud83d\udeac", "\ud83d\udd14", + "\ud83d\udd15", "\ud83d\udeaa", "\ud83d\udd2c", "\ud83d\udd2d", "\ud83d\udd2e", "\ud83d\udd26", + "\ud83d\udd0b", "\ud83d\udd0c", "\ud83d\udcdc", "\ud83d\udcd7", "\ud83d\udcd8", "\ud83d\udcd9", + "\ud83d\udcda", "\ud83d\udcd4", "\ud83d\udcd2", "\ud83d\udcd1", "\ud83d\udcd3", "\ud83d\udcd5", + "\ud83d\udcd6", "\ud83d\udcf0", "\ud83d\udcdb", "\ud83c\udf83", "\ud83c\udf84", "\ud83c\udf80", + "\ud83c\udf81", "\ud83c\udf82", "\ud83c\udf88", "\ud83c\udf86", "\ud83c\udf87", "\ud83c\udf89", + "\ud83c\udf8a", "\ud83c\udf8d", "\ud83c\udf8f", "\ud83c\udf8c", "\ud83c\udf90", "\ud83c\udf8b", + "\ud83c\udf8e", "\ud83d\udcf1", "\ud83d\udcf2", "\ud83d\udcdf", "\u260e", "\ud83d\udcde", + "\ud83d\udce0", "\ud83d\udce6", "\u2709", "\ud83d\udce8", "\ud83d\udce9", "\ud83d\udcea", + "\ud83d\udceb", "\ud83d\udced", "\ud83d\udcec", "\ud83d\udcee", "\ud83d\udce4", "\ud83d\udce5", + "\ud83d\udcef", "\ud83d\udce2", "\ud83d\udce3", "\ud83d\udce1", "\ud83d\udcac", "\ud83d\udcad", + "\u2712", "\u270f", "\ud83d\udcdd", "\ud83d\udccf", "\ud83d\udcd0", "\ud83d\udccd", + "\ud83d\udccc", "\ud83d\udcce", "\u2702", "\ud83d\udcba", "\ud83d\udcbb", "\ud83d\udcbd", + "\ud83d\udcbe", "\ud83d\udcbf", "\ud83d\udcc6", "\ud83d\udcc5", "\ud83d\udcc7", "\ud83d\udccb", + "\ud83d\udcc1", "\ud83d\udcc2", "\ud83d\udcc3", "\ud83d\udcc4", "\ud83d\udcca", "\ud83d\udcc8", + "\ud83d\udcc9", "\u26fa", "\ud83c\udfa1", "\ud83c\udfa2", "\ud83c\udfa0", "\ud83c\udfaa", + "\ud83c\udfa8", "\ud83c\udfac", "\ud83c\udfa5", "\ud83d\udcf7", "\ud83d\udcf9", "\ud83c\udfa6", + "\ud83c\udfad", "\ud83c\udfab", "\ud83c\udfae", "\ud83c\udfb2", "\ud83c\udfb0", "\ud83c\udccf", + "\ud83c\udfb4", "\ud83c\udc04", "\ud83c\udfaf", "\ud83d\udcfa", "\ud83d\udcfb", "\ud83d\udcc0", + "\ud83d\udcfc", "\ud83c\udfa7", "\ud83c\udfa4", "\ud83c\udfb5", "\ud83c\udfb6", "\ud83c\udfbc", + "\ud83c\udfbb", "\ud83c\udfb9", "\ud83c\udfb7", "\ud83c\udfba", "\ud83c\udfb8", "\u303d", + }, "emoji-objects.png"), + new StaticEmojiPageModel(R.drawable.emoji_category_nature, new String[] { + "\ud83d\udc15", "\ud83d\udc36", "\ud83d\udc29", "\ud83d\udc08", "\ud83d\udc31", "\ud83d\udc00", + "\ud83d\udc01", "\ud83d\udc2d", "\ud83d\udc39", "\ud83d\udc22", "\ud83d\udc07", "\ud83d\udc30", + "\ud83d\udc13", "\ud83d\udc14", "\ud83d\udc23", "\ud83d\udc24", "\ud83d\udc25", "\ud83d\udc26", + "\ud83d\udc0f", "\ud83d\udc11", "\ud83d\udc10", "\ud83d\udc3a", "\ud83d\udc03", "\ud83d\udc02", + "\ud83d\udc04", "\ud83d\udc2e", "\ud83d\udc34", "\ud83d\udc17", "\ud83d\udc16", "\ud83d\udc37", + "\ud83d\udc3d", "\ud83d\udc38", "\ud83d\udc0d", "\ud83d\udc3c", "\ud83d\udc27", "\ud83d\udc18", + "\ud83d\udc28", "\ud83d\udc12", "\ud83d\udc35", "\ud83d\udc06", "\ud83d\udc2f", "\ud83d\udc3b", + "\ud83d\udc2b", "\ud83d\udc2a", "\ud83d\udc0a", "\ud83d\udc33", "\ud83d\udc0b", "\ud83d\udc1f", + "\ud83d\udc20", "\ud83d\udc21", "\ud83d\udc19", "\ud83d\udc1a", "\ud83d\udc2c", "\ud83d\udc0c", + "\ud83d\udc1b", "\ud83d\udc1c", "\ud83d\udc1d", "\ud83d\udc1e", "\ud83d\udc32", "\ud83d\udc09", + "\ud83d\udc3e", "\ud83c\udf78", "\ud83c\udf7a", "\ud83c\udf7b", "\ud83c\udf77", "\ud83c\udf79", + "\ud83c\udf76", "\u2615", "\ud83c\udf75", "\ud83c\udf7c", "\ud83c\udf74", "\ud83c\udf68", + "\ud83c\udf67", "\ud83c\udf66", "\ud83c\udf69", "\ud83c\udf70", "\ud83c\udf6a", "\ud83c\udf6b", + "\ud83c\udf6c", "\ud83c\udf6d", "\ud83c\udf6e", "\ud83c\udf6f", "\ud83c\udf73", "\ud83c\udf54", + "\ud83c\udf5f", "\ud83c\udf5d", "\ud83c\udf55", "\ud83c\udf56", "\ud83c\udf57", "\ud83c\udf64", + "\ud83c\udf63", "\ud83c\udf71", "\ud83c\udf5e", "\ud83c\udf5c", "\ud83c\udf59", "\ud83c\udf5a", + "\ud83c\udf5b", "\ud83c\udf72", "\ud83c\udf65", "\ud83c\udf62", "\ud83c\udf61", "\ud83c\udf58", + "\ud83c\udf60", "\ud83c\udf4c", "\ud83c\udf4e", "\ud83c\udf4f", "\ud83c\udf4a", "\ud83c\udf4b", + "\ud83c\udf44", "\ud83c\udf45", "\ud83c\udf46", "\ud83c\udf47", "\ud83c\udf48", "\ud83c\udf49", + "\ud83c\udf50", "\ud83c\udf51", "\ud83c\udf52", "\ud83c\udf53", "\ud83c\udf4d", "\ud83c\udf30", + "\ud83c\udf31", "\ud83c\udf32", "\ud83c\udf33", "\ud83c\udf34", "\ud83c\udf35", "\ud83c\udf37", + "\ud83c\udf38", "\ud83c\udf39", "\ud83c\udf40", "\ud83c\udf41", "\ud83c\udf42", "\ud83c\udf43", + "\ud83c\udf3a", "\ud83c\udf3b", "\ud83c\udf3c", "\ud83c\udf3d", "\ud83c\udf3e", "\ud83c\udf3f", + "\u2600", "\ud83c\udf08", "\u26c5", "\u2601", "\ud83c\udf01", "\ud83c\udf02", + "\u2614", "\ud83d\udca7", "\u26a1", "\ud83c\udf00", "\u2744", "\u26c4", + "\ud83c\udf19", "\ud83c\udf1e", "\ud83c\udf1d", "\ud83c\udf1a", "\ud83c\udf1b", "\ud83c\udf1c", + "\ud83c\udf11", "\ud83c\udf12", "\ud83c\udf13", "\ud83c\udf14", "\ud83c\udf15", "\ud83c\udf16", + "\ud83c\udf17", "\ud83c\udf18", "\ud83c\udf91", "\ud83c\udf04", "\ud83c\udf05", "\ud83c\udf07", + "\ud83c\udf06", "\ud83c\udf03", "\ud83c\udf0c", "\ud83c\udf09", "\ud83c\udf0a", "\ud83c\udf0b", + "\ud83c\udf0e", "\ud83c\udf0f", "\ud83c\udf0d", "\ud83c\udf10", + }, "emoji-nature.png"), + new StaticEmojiPageModel(R.drawable.emoji_category_places, new String[] { + "\ud83c\udfe0", "\ud83c\udfe1", "\ud83c\udfe2", "\ud83c\udfe3", "\ud83c\udfe4", "\ud83c\udfe5", + "\ud83c\udfe6", "\ud83c\udfe7", "\ud83c\udfe8", "\ud83c\udfe9", "\ud83c\udfea", "\ud83c\udfeb", + "\u26ea", "\u26f2", "\ud83c\udfec", "\ud83c\udfef", "\ud83c\udff0", "\ud83c\udfed", + "\ud83d\uddfb", "\ud83d\uddfc", "\ud83d\uddfd", "\ud83d\uddfe", "\ud83d\uddff", "\u2693", + "\ud83c\udfee", "\ud83d\udc88", "\ud83d\udd27", "\ud83d\udd28", "\ud83d\udd29", "\ud83d\udebf", + "\ud83d\udec1", "\ud83d\udec0", "\ud83d\udebd", "\ud83d\udebe", "\ud83c\udfbd", "\ud83c\udfa3", + "\ud83c\udfb1", "\ud83c\udfb3", "\u26be", "\u26f3", "\ud83c\udfbe", "\u26bd", + "\ud83c\udfbf", "\ud83c\udfc0", "\ud83c\udfc1", "\ud83c\udfc2", "\ud83c\udfc3", "\ud83c\udfc4", + "\ud83c\udfc6", "\ud83c\udfc7", "\ud83d\udc0e", "\ud83c\udfc8", "\ud83c\udfc9", "\ud83c\udfca", + "\ud83d\ude82", "\ud83d\ude83", "\ud83d\ude84", "\ud83d\ude85", "\ud83d\ude86", "\ud83d\ude87", + "\u24c2", "\ud83d\ude88", "\ud83d\ude8a", "\ud83d\ude8b", "\ud83d\ude8c", "\ud83d\ude8d", + "\ud83d\ude8e", "\ud83d\ude8f", "\ud83d\ude90", "\ud83d\ude91", "\ud83d\ude92", "\ud83d\ude93", + "\ud83d\ude94", "\ud83d\ude95", "\ud83d\ude96", "\ud83d\ude97", "\ud83d\ude98", "\ud83d\ude99", + "\ud83d\ude9a", "\ud83d\ude9b", "\ud83d\ude9c", "\ud83d\ude9d", "\ud83d\ude9e", "\ud83d\ude9f", + "\ud83d\udea0", "\ud83d\udea1", "\ud83d\udea2", "\ud83d\udea3", "\ud83d\ude81", "\u2708", + "\ud83d\udec2", "\ud83d\udec3", "\ud83d\udec4", "\ud83d\udec5", "\u26f5", "\ud83d\udeb2", + "\ud83d\udeb3", "\ud83d\udeb4", "\ud83d\udeb5", "\ud83d\udeb7", "\ud83d\udeb8", "\ud83d\ude89", + "\ud83d\ude80", "\ud83d\udea4", "\ud83d\udeb6", "\u26fd", "\ud83c\udd7f", "\ud83d\udea5", + "\ud83d\udea6", "\ud83d\udea7", "\ud83d\udea8", "\u2668", "\ud83d\udc8c", "\ud83d\udc8d", + "\ud83d\udc8e", "\ud83d\udc90", "\ud83d\udc92", + }, "emoji-places.png"), + new StaticEmojiPageModel(R.drawable.emoji_category_symbol, new String[] { + "\ud83d\udd1d", "\ud83d\udd19", "\ud83d\udd1b", "\ud83d\udd1c", "\ud83d\udd1a", "\u23f3", + "\u231b", "\u23f0", "\u2648", "\u2649", "\u264a", "\u264b", + "\u264c", "\u264d", "\u264e", "\u264f", "\u2650", "\u2651", + "\u2652", "\u2653", "\u26ce", "\ud83d\udd31", "\ud83d\udd2f", "\ud83d\udebb", + "\ud83d\udeae", "\ud83d\udeaf", "\ud83d\udeb0", "\ud83d\udeb1", "\ud83c\udd70", "\ud83c\udd71", + "\ud83c\udd8e", "\ud83c\udd7e", "\ud83d\udcae", "\ud83d\udcaf", "\ud83d\udd20", "\ud83d\udd21", + "\ud83d\udd22", "\ud83d\udd23", "\ud83d\udd24", "\u27bf", "\ud83d\udcf6", "\ud83d\udcf3", + "\ud83d\udcf4", "\ud83d\udcf5", "\ud83d\udeb9", "\ud83d\udeba", "\ud83d\udebc", "\u267f", + "\u267b", "\ud83d\udead", "\ud83d\udea9", "\u26a0", "\ud83c\ude01", "\ud83d\udd1e", + "\u26d4", "\ud83c\udd92", "\ud83c\udd97", "\ud83c\udd95", "\ud83c\udd98", "\ud83c\udd99", + "\ud83c\udd93", "\ud83c\udd96", "\ud83c\udd9a", "\ud83c\ude32", "\ud83c\ude33", "\ud83c\ude34", + "\ud83c\ude35", "\ud83c\ude36", "\ud83c\ude37", "\ud83c\ude38", "\ud83c\ude39", "\ud83c\ude02", + "\ud83c\ude3a", "\ud83c\ude50", "\ud83c\ude51", "\u3299", "\u00ae", "\u00a9", + "\u2122", "\ud83c\ude1a", "\ud83c\ude2f", "\u3297", "\u2b55", "\u274c", + "\u274e", "\u2139", "\ud83d\udeab", "\u2705", "\u2714", "\ud83d\udd17", + "\u2734", "\u2733", "\u2795", "\u2796", "\u2716", "\u2797", + "\ud83d\udca0", "\ud83d\udca1", "\ud83d\udca4", "\ud83d\udca2", "\ud83d\udd25", "\ud83d\udca5", + "\ud83d\udca8", "\ud83d\udca6", "\ud83d\udcab", "\ud83d\udd5b", "\ud83d\udd67", "\ud83d\udd50", + "\ud83d\udd5c", "\ud83d\udd51", "\ud83d\udd5d", "\ud83d\udd52", "\ud83d\udd5e", "\ud83d\udd53", + "\ud83d\udd5f", "\ud83d\udd54", "\ud83d\udd60", "\ud83d\udd55", "\ud83d\udd61", "\ud83d\udd56", + "\ud83d\udd62", "\ud83d\udd57", "\ud83d\udd63", "\ud83d\udd58", "\ud83d\udd64", "\ud83d\udd59", + "\ud83d\udd65", "\ud83d\udd5a", "\ud83d\udd66", "\u2195", "\u2b06", "\u2197", + "\u27a1", "\u2198", "\u2b07", "\u2199", "\u2b05", "\u2196", + "\u2194", "\u2934", "\u2935", "\u23ea", "\u23eb", "\u23ec", + "\u23e9", "\u25c0", "\u25b6", "\ud83d\udd3d", "\ud83d\udd3c", "\u2747", + "\u2728", "\ud83d\udd34", "\ud83d\udd35", "\u26aa", "\u26ab", "\ud83d\udd33", + "\ud83d\udd32", "\u2b50", "\ud83c\udf1f", "\ud83c\udf20", "\u25ab", "\u25aa", + "\u25fd", "\u25fe", "\u25fb", "\u25fc", "\u2b1c", "\u2b1b", + "\ud83d\udd38", "\ud83d\udd39", "\ud83d\udd36", "\ud83d\udd37", "\ud83d\udd3a", "\ud83d\udd3b", + "\u2754", "\u2753", "\u2755", "\u2757", "\u203c", "\u2049", + "\u3030", "\u27b0", "\u2660", "\u2665", "\u2663", "\u2666", + "\ud83c\udd94", "\ud83d\udd11", "\u21a9", "\ud83c\udd91", "\ud83d\udd0d", "\ud83d\udd12", + "\ud83d\udd13", "\u21aa", "\ud83d\udd10", "\u2611", "\ud83d\udd18", "\ud83d\udd0e", + "\ud83d\udd16", "\ud83d\udd0f", "\ud83d\udd03", "\ud83d\udd00", "\ud83d\udd01", "\ud83d\udd02", + "\ud83d\udd04", "\ud83d\udce7", "\ud83d\udd05", "\ud83d\udd06", "\ud83d\udd07", "\ud83d\udd08", + "\ud83d\udd09", "\ud83d\udd0a", + }, "emoji-symbol.png"), + new StaticEmojiPageModel(R.drawable.emoji_category_emoticons, new String[] { + "=-O", ":-P", ";-)", ":-(", ":-)", ":-!", + ":-$", "B-)", ":O", ":-*", ":-D", ":'(", + ":-\\", "O:-)", ":-[", + }, null)); +} diff --git a/src/org/thoughtcrime/securesms/components/emoji/EmojiProvider.java b/src/org/thoughtcrime/securesms/components/emoji/EmojiProvider.java index 1d5b9234ef..39ab34cf29 100644 --- a/src/org/thoughtcrime/securesms/components/emoji/EmojiProvider.java +++ b/src/org/thoughtcrime/securesms/components/emoji/EmojiProvider.java @@ -13,7 +13,6 @@ import android.graphics.drawable.Drawable.Callback; import android.os.AsyncTask; import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; -import android.support.annotation.Nullable; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.util.Log; @@ -24,7 +23,6 @@ import org.thoughtcrime.securesms.util.BitmapDecodingException; import org.thoughtcrime.securesms.util.BitmapUtil; import org.thoughtcrime.securesms.util.FutureTaskListener; import org.thoughtcrime.securesms.util.ListenableFutureTask; -import org.thoughtcrime.securesms.util.ResUtil; import org.thoughtcrime.securesms.util.Util; import java.io.IOException; @@ -70,19 +68,18 @@ public class EmojiProvider { } private EmojiProvider(Context context) { - int[] pages = ResUtil.getResourceIds(context, R.array.emoji_categories); - this.context = context.getApplicationContext(); this.drawHeight = Math.min(context.getResources().getDimension(R.dimen.emoji_drawer_size), EMOJI_RAW_HEIGHT); double drawScale = drawHeight / EMOJI_RAW_HEIGHT; this.drawWidth = EMOJI_RAW_WIDTH * drawScale; this.verticalPad = EMOJI_VERT_PAD * drawScale; Log.w(TAG, "draw size: " + drawWidth + "x" + drawHeight); - for (int i = 0; i < pages.length; i++) { - final EmojiPageBitmap page = new EmojiPageBitmap(i); - final int[] codePoints = context.getResources().getIntArray(pages[i]); - for (int j = 0; j < codePoints.length; j++) { - offsets.put(codePoints[j], new DrawInfo(page, j)); + for (EmojiPageModel page : EmojiPages.PAGES) { + if (page.hasSpriteMap()) { + final EmojiPageBitmap pageBitmap = new EmojiPageBitmap(page); + for (int i=0; i < page.getEmoji().length; i++) { + offsets.put(Character.codePointAt(page.getEmoji()[i], 0), new DrawInfo(pageBitmap, i)); + } } } } @@ -108,7 +105,9 @@ public class EmojiProvider { } private Drawable getEmojiDrawable(DrawInfo drawInfo, double size) { - if (drawInfo == null) return null; + if (drawInfo == null) { + return null; + } final EmojiDrawable drawable = new EmojiDrawable(drawInfo, drawWidth, drawHeight); drawable.setBounds(0, 0, (int)(drawWidth * size), (int)(drawHeight * size)); @@ -151,7 +150,6 @@ public class EmojiProvider { @Override public void draw(Canvas canvas) { if (bmp == null) { - Log.w(TAG, "no-op draw(" + info.page + ", " + info.index + ")"); return; } @@ -170,7 +168,6 @@ public class EmojiProvider { @TargetApi(VERSION_CODES.HONEYCOMB_MR1) public void setBitmap(Bitmap bitmap) { Util.assertMainThread(); - Log.w(TAG, "setBitmap(" + info.page + ", " + info.index + ")"); if (VERSION.SDK_INT < VERSION_CODES.HONEYCOMB_MR1 || bmp == null || !bmp.sameAs(bitmap)) { bmp = bitmap; invalidateSelf(); @@ -208,12 +205,12 @@ public class EmojiProvider { } private class EmojiPageBitmap { - private int page; + private EmojiPageModel model; private SoftReference bitmapReference; private ListenableFutureTask task; - public EmojiPageBitmap(int page) { - this.page = page; + public EmojiPageBitmap(EmojiPageModel model) { + this.model = model; } private ListenableFutureTask get() { @@ -227,7 +224,7 @@ public class EmojiProvider { Callable callable = new Callable() { @Override public Bitmap call() throws Exception { try { - Log.w(TAG, "loading page " + page); + Log.w(TAG, "loading page " + model.getSprite()); return loadPage(); } catch (IOException ioe) { Log.w(TAG, ioe); @@ -254,25 +251,24 @@ public class EmojiProvider { if (bitmapReference != null && bitmapReference.get() != null) return bitmapReference.get(); try { - final String file = "emoji-" + page + ".png"; - final InputStream measureStream = context.getAssets().open(file); - final InputStream bitmapStream = context.getAssets().open(file); + final InputStream measureStream = context.getAssets().open(model.getSprite()); + final InputStream bitmapStream = context.getAssets().open(model.getSprite()); final Bitmap bitmap = BitmapUtil.createScaledBitmap(measureStream, bitmapStream, (float) drawHeight / (float) EMOJI_RAW_HEIGHT); bitmapReference = new SoftReference<>(bitmap); - Log.w(TAG, "onPageLoaded(" + page + ")"); + Log.w(TAG, "onPageLoaded(" + model.getSprite() + ")"); return bitmap; } catch (IOException ioe) { Log.w(TAG, ioe); throw ioe; } catch (BitmapDecodingException bde) { - Log.w(TAG, "page " + page + " failed."); + Log.w(TAG, "page " + model + " failed."); Log.w(TAG, bde); throw new AssertionError("emoji sprite asset is corrupted or android decoding is broken"); } } @Override public String toString() { - return Integer.toString(page); + return model.getSprite(); } } } diff --git a/src/org/thoughtcrime/securesms/components/emoji/EmojiView.java b/src/org/thoughtcrime/securesms/components/emoji/EmojiView.java new file mode 100644 index 0000000000..946161bc83 --- /dev/null +++ b/src/org/thoughtcrime/securesms/components/emoji/EmojiView.java @@ -0,0 +1,79 @@ +package org.thoughtcrime.securesms.components.emoji; + +import android.annotation.TargetApi; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Paint.Align; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.os.Build.VERSION_CODES; +import android.support.annotation.NonNull; +import android.util.AttributeSet; +import android.view.View; + +import com.google.common.base.Optional; + +public class EmojiView extends View implements Drawable.Callback { + private String emoji; + private Drawable drawable; + + private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Rect textBounds = new Rect(); + + public EmojiView(Context context) { + super(context); + } + + public EmojiView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public EmojiView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @TargetApi(VERSION_CODES.LOLLIPOP) + public EmojiView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + public void setEmoji(String emoji) { + this.emoji = emoji; + this.drawable = EmojiProvider.getInstance(getContext()) + .getEmojiDrawable(Character.codePointAt(emoji, 0), + EmojiProvider.EMOJI_FULL); + postInvalidate(); + } + + @Override protected void onDraw(Canvas canvas) { + if (drawable != null) { + drawable.setBounds(getPaddingLeft(), + getPaddingTop(), + getWidth() - getPaddingRight(), + getHeight() - getPaddingBottom()); + drawable.setCallback(this); + drawable.draw(canvas); + } else { + float targetFontSize = 0.75f * getHeight() - getPaddingTop() - getPaddingBottom(); + paint.setTextSize(targetFontSize); + paint.setColor(Color.BLACK); + paint.getTextBounds(emoji, 0, emoji.length(), textBounds); + float overflow = textBounds.width() / (getWidth() - getPaddingLeft() - getPaddingRight()); + if (overflow > 1f) { + paint.setTextSize(targetFontSize / overflow); + } + canvas.drawText(emoji, 0.5f * (getWidth() - textBounds.width()), 0.5f * (getHeight() + textBounds.height()), paint); + } + } + + @Override public void invalidateDrawable(@NonNull Drawable drawable) { + super.invalidateDrawable(drawable); + postInvalidate(); + } + + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } +} diff --git a/src/org/thoughtcrime/securesms/components/emoji/RecentEmojiPageModel.java b/src/org/thoughtcrime/securesms/components/emoji/RecentEmojiPageModel.java index 1ab96a006d..67cdd75f5e 100644 --- a/src/org/thoughtcrime/securesms/components/emoji/RecentEmojiPageModel.java +++ b/src/org/thoughtcrime/securesms/components/emoji/RecentEmojiPageModel.java @@ -5,7 +5,6 @@ import android.content.SharedPreferences; import android.os.AsyncTask; import android.preference.PreferenceManager; import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.util.Log; import com.fasterxml.jackson.databind.type.CollectionType; @@ -20,25 +19,23 @@ import java.util.LinkedHashSet; public class RecentEmojiPageModel implements EmojiPageModel { private static final String TAG = RecentEmojiPageModel.class.getSimpleName(); - private static final String EMOJI_LRU_PREFERENCE = "pref_recent_emoji"; + private static final String EMOJI_LRU_PREFERENCE = "pref_recent_emoji2"; private static final int EMOJI_LRU_SIZE = 50; - private final SharedPreferences prefs; - private final LinkedHashSet recentlyUsed; + private final SharedPreferences prefs; + private final LinkedHashSet recentlyUsed; public RecentEmojiPageModel(Context context) { this.prefs = PreferenceManager.getDefaultSharedPreferences(context); this.recentlyUsed = getPersistedCache(); } - private LinkedHashSet getPersistedCache() { + private LinkedHashSet getPersistedCache() { String serialized = prefs.getString(EMOJI_LRU_PREFERENCE, "[]"); - LinkedHashSet recentlyUsedStrings; try { CollectionType collectionType = TypeFactory.defaultInstance() .constructCollectionType(LinkedHashSet.class, String.class); - recentlyUsedStrings = JsonUtils.getMapper().readValue(serialized, collectionType); - return fromHexString(recentlyUsedStrings); + return JsonUtils.getMapper().readValue(serialized, collectionType); } catch (IOException e) { Log.w(TAG, e); return new LinkedHashSet<>(); @@ -49,32 +46,40 @@ public class RecentEmojiPageModel implements EmojiPageModel { return R.drawable.emoji_category_recent; } - @Override public int[] getCodePoints() { + @Override public String[] getEmoji() { return toReversePrimitiveArray(recentlyUsed); } + @Override public boolean hasSpriteMap() { + return false; + } + + @Override public String getSprite() { + return null; + } + @Override public boolean isDynamic() { return true; } - public void onCodePointSelected(int codePoint) { - Log.w(TAG, "onCodePointSelected(" + codePoint + ")"); - recentlyUsed.remove(codePoint); - recentlyUsed.add(codePoint); + public void onCodePointSelected(String emoji) { + Log.w(TAG, "onCodePointSelected(" + emoji + ")"); + recentlyUsed.remove(emoji); + recentlyUsed.add(emoji); if (recentlyUsed.size() > EMOJI_LRU_SIZE) { - Iterator iterator = recentlyUsed.iterator(); + Iterator iterator = recentlyUsed.iterator(); iterator.next(); iterator.remove(); } - final LinkedHashSet latestRecentlyUsed = new LinkedHashSet<>(recentlyUsed); + final LinkedHashSet latestRecentlyUsed = new LinkedHashSet<>(recentlyUsed); new AsyncTask() { @Override protected Void doInBackground(Void... params) { try { - String serialized = JsonUtils.toJson(toHexString(latestRecentlyUsed)); + String serialized = JsonUtils.toJson(latestRecentlyUsed); prefs.edit() .putString(EMOJI_LRU_PREFERENCE, serialized) .apply(); @@ -87,30 +92,12 @@ public class RecentEmojiPageModel implements EmojiPageModel { }.execute(); } - private LinkedHashSet fromHexString(@Nullable LinkedHashSet stringSet) { - final LinkedHashSet integerSet = new LinkedHashSet<>(stringSet != null ? stringSet.size() : 0); - if (stringSet != null) { - for (String hexString : stringSet) { - integerSet.add(Integer.valueOf(hexString, 16)); - } + private String[] toReversePrimitiveArray(@NonNull LinkedHashSet emojiSet) { + String[] emojis = new String[emojiSet.size()]; + int i = emojiSet.size() - 1; + for (String emoji : emojiSet) { + emojis[i--] = emoji; } - return integerSet; - } - - private LinkedHashSet toHexString(@NonNull LinkedHashSet integerSet) { - final LinkedHashSet stringSet = new LinkedHashSet<>(integerSet.size()); - for (Integer integer : integerSet) { - stringSet.add(Integer.toHexString(integer)); - } - return stringSet; - } - - private int[] toReversePrimitiveArray(@NonNull LinkedHashSet integerSet) { - int[] ints = new int[integerSet.size()]; - int i = integerSet.size() - 1; - for (Integer integer : integerSet) { - ints[i--] = integer; - } - return ints; + return emojis; } } diff --git a/src/org/thoughtcrime/securesms/components/emoji/StaticEmojiPageModel.java b/src/org/thoughtcrime/securesms/components/emoji/StaticEmojiPageModel.java index 1e814ea5f0..a6cd52b967 100644 --- a/src/org/thoughtcrime/securesms/components/emoji/StaticEmojiPageModel.java +++ b/src/org/thoughtcrime/securesms/components/emoji/StaticEmojiPageModel.java @@ -2,22 +2,33 @@ package org.thoughtcrime.securesms.components.emoji; import android.support.annotation.DrawableRes; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; public class StaticEmojiPageModel implements EmojiPageModel { - @DrawableRes private final int icon; - @NonNull private final int[] codePoints; + @DrawableRes private final int icon; + @NonNull private final String[] emoji; + @Nullable private final String sprite; - public StaticEmojiPageModel(@DrawableRes int icon, @NonNull int[] codePoints) { - this.icon = icon; - this.codePoints = codePoints; + public StaticEmojiPageModel(@DrawableRes int icon, @NonNull String[] emoji, @Nullable String sprite) { + this.icon = icon; + this.emoji = emoji; + this.sprite = sprite; } public int getIconRes() { return icon; } - @NonNull public int[] getCodePoints() { - return codePoints; + @NonNull public String[] getEmoji() { + return emoji; + } + + @Override public boolean hasSpriteMap() { + return sprite != null; + } + + @Override @Nullable public String getSprite() { + return sprite; } @Override public boolean isDynamic() {