{"id":"d972256b-ead4-4214-a587-3057d55eabf1","shortId":"2aZ2Sa","kind":"skill","title":"cometchat-android-v5-customization","tagline":"Customize CometChat components beyond theming — custom message templates, DataSource decorators, event listeners, and custom view slots.","description":"> **Companion skills:** `cometchat-android-v5-components` provides the component\n> catalog; `cometchat-android-v5-theming` covers visual styling;\n> `cometchat-android-v5-extensions` covers the extension architecture.\n\n## Purpose\n\nThis skill teaches how to customize CometChat components beyond what theming provides. It covers custom message templates, the DataSource/DataSourceDecorator pattern, ChatConfigurator, event listeners, and custom view slots.\n\n---\n\n## Use this skill when\n\n- \"Customize the message list\"\n- \"Add a custom message bubble\"\n- \"Listen to message events\"\n- \"Add a custom action to message options\"\n- \"Filter conversations\"\n\n## Do not use this skill when\n\n- Changing colors/fonts → use `cometchat-android-v5-theming`\n- Enabling a packaged feature → use `cometchat-android-v5-features`\n- Setting up init/login → use `cometchat-android-v5-core`\n\n---\n\n## 1. CometChatMessageTemplate\n\nTemplates define how message bubbles are rendered. Each template maps a message `type` + `category` to custom views.\n\n**Java:**\n```java\nCometChatMessageTemplate template = new CometChatMessageTemplate()\n    .setType(CometChatConstants.MESSAGE_TYPE_TEXT)\n    .setCategory(CometChatConstants.CATEGORY_MESSAGE)\n    .setContentView(new MessagesViewHolderListener() {\n        @Override\n        public View createView(Context context, CometChatMessageBubble messageBubble,\n                               UIKitConstants.MessageBubbleAlignment alignment) {\n            // Return your custom view\n            return LayoutInflater.from(context).inflate(R.layout.custom_text_bubble, null);\n        }\n\n        @Override\n        public void bindView(Context context, View createdView, BaseMessage message,\n                             UIKitConstants.MessageBubbleAlignment alignment,\n                             RecyclerView.ViewHolder holder, List<BaseMessage> messageList,\n                             int position) {\n            // Bind data to your custom view\n            TextView textView = createdView.findViewById(R.id.customText);\n            textView.setText(((TextMessage) message).getText());\n        }\n    })\n    .setOptions((context, baseMessage, group) -> {\n        // Return custom message options (long-press menu)\n        List<CometChatMessageOption> options = new ArrayList<>();\n        options.add(new CometChatMessageOption(\"custom_action\", \"Custom Action\",\n            R.drawable.ic_custom, () -> { /* handle click */ }));\n        return options;\n    });\n\n// Apply to message list\nmessageList.setTemplates(Collections.singletonList(template));\n```\n\n**Kotlin:**\n```kotlin\nval template = CometChatMessageTemplate()\n    .setType(CometChatConstants.MESSAGE_TYPE_TEXT)\n    .setCategory(CometChatConstants.CATEGORY_MESSAGE)\n    .setContentView(object : MessagesViewHolderListener() {\n        override fun createView(context: Context, messageBubble: CometChatMessageBubble,\n                                alignment: UIKitConstants.MessageBubbleAlignment): View {\n            return LayoutInflater.from(context).inflate(R.layout.custom_text_bubble, null)\n        }\n\n        override fun bindView(context: Context, createdView: View, message: BaseMessage,\n                              alignment: UIKitConstants.MessageBubbleAlignment,\n                              holder: RecyclerView.ViewHolder, messageList: List<BaseMessage>,\n                              position: Int) {\n            val textView = createdView.findViewById<TextView>(R.id.customText)\n            textView.text = (message as TextMessage).text\n        }\n    })\n    .setOptions { context, baseMessage, group ->\n        listOf(CometChatMessageOption(\"custom_action\", \"Custom Action\",\n            R.drawable.ic_custom) { /* handle click */ })\n    }\n\nmessageList.setTemplates(listOf(template))\n```\n\n### Template view slots\n\n| Slot | Method | Description |\n|---|---|---|\n| `bubbleView` | `setBubbleView(MessagesViewHolderListener)` | Entire message bubble |\n| `headerView` | `setHeaderView(MessagesViewHolderListener)` | Above the bubble |\n| `contentView` | `setContentView(MessagesViewHolderListener)` | Inside the bubble |\n| `bottomView` | `setBottomView(MessagesViewHolderListener)` | Below the content, inside bubble |\n| `footerView` | `setFooterView(MessagesViewHolderListener)` | Below the bubble |\n| `statusInfoView` | `setStatusInfoView(MessagesViewHolderListener)` | Status info area |\n| `replyView` | `setReplyView(MessagesViewHolderListener)` | Reply preview above bubble |\n\n---\n\n## 2. CometChatMessageOption\n\nCustom actions in the message long-press menu.\n\n**Java:**\n```java\nCometChatMessageOption option = new CometChatMessageOption(\n    \"bookmark\",                    // unique ID\n    \"Bookmark\",                    // title\n    R.drawable.ic_bookmark,        // icon\n    () -> {                        // onClick\n        // Handle bookmark action\n    }\n);\n```\n\n---\n\n## 3. DataSource and DataSourceDecorator\n\nThe `DataSource` interface defines how messages are rendered and what options are available. `DataSourceDecorator` wraps an existing DataSource to add or modify behavior without replacing it.\n\n**Java:**\n```java\npublic class CustomDataSource extends DataSourceDecorator {\n    public CustomDataSource(DataSource dataSource) {\n        super(dataSource);\n    }\n\n    @Override\n    public List<CometChatMessageOption> getTextMessageOptions(Context context,\n            BaseMessage baseMessage, Group group, AdditionParameter additionParameter) {\n        List<CometChatMessageOption> options = super.getTextMessageOptions(context,\n            baseMessage, group, additionParameter);\n        // Add custom option\n        options.add(new CometChatMessageOption(\"translate\", \"Translate\",\n            R.drawable.ic_translate, () -> { /* translate */ }));\n        return options;\n    }\n}\n```\n\n**Kotlin:**\n```kotlin\nclass CustomDataSource(dataSource: DataSource) : DataSourceDecorator(dataSource) {\n    override fun getTextMessageOptions(context: Context, baseMessage: BaseMessage,\n            group: Group?, additionParameter: AdditionParameter): List<CometChatMessageOption> {\n        val options = super.getTextMessageOptions(context, baseMessage, group, additionParameter).toMutableList()\n        options.add(CometChatMessageOption(\"translate\", \"Translate\",\n            R.drawable.ic_translate) { /* translate */ })\n        return options\n    }\n}\n```\n\n### Register via ChatConfigurator\n\n**Java:**\n```java\nChatConfigurator.enable(dataSource -> new CustomDataSource(dataSource));\n```\n\n**Kotlin:**\n```kotlin\nChatConfigurator.enable { dataSource -> CustomDataSource(dataSource) }\n```\n\n---\n\n## 4. Event system\n\nCometChat provides event classes for reacting to chat events. Register listeners with a unique tag.\n\n### CometChatMessageEvents\n\n**Java:**\n```java\nCometChatMessageEvents.addListener(\"unique-tag\", new CometChatMessageEvents() {\n    @Override\n    public void ccMessageSent(BaseMessage baseMessage, int status) {\n        // Message sent\n    }\n\n    @Override\n    public void onTextMessageReceived(TextMessage textMessage) {\n        // Text message received\n    }\n\n    @Override\n    public void onMessageReactionAdded(ReactionEvent reactionEvent) {\n        // Reaction added\n    }\n});\n\n// Remove when done\nCometChatMessageEvents.removeListener(\"unique-tag\");\n```\n\n**Kotlin:**\n```kotlin\nCometChatMessageEvents.addListener(\"unique-tag\", object : CometChatMessageEvents() {\n    override fun ccMessageSent(baseMessage: BaseMessage, status: Int) {\n        // Message sent\n    }\n\n    override fun onTextMessageReceived(textMessage: TextMessage) {\n        // Text message received\n    }\n\n    override fun onMessageReactionAdded(reactionEvent: ReactionEvent) {\n        // Reaction added\n    }\n})\n\n// Remove when done\nCometChatMessageEvents.removeListener(\"unique-tag\")\n```\n\n### CometChatUserEvents\n\n```java\nCometChatUserEvents.addUserListener(\"unique-tag\", new CometChatUserEvents() {\n    @Override\n    public void ccUserBlocked(User user) { }\n\n    @Override\n    public void ccUserUnblocked(User user) { }\n});\n```\n\n### CometChatGroupEvents\n\n```java\nCometChatGroupEvents.addGroupListener(\"unique-tag\", new CometChatGroupEvents() {\n    @Override\n    public void ccGroupCreated(Group group) { }\n    @Override\n    public void ccGroupDeleted(Group group) { }\n    @Override\n    public void ccGroupMemberJoined(User joinedUser, Group joinedGroup) { }\n    @Override\n    public void ccGroupMemberKicked(Action action, User kicked, User kickedBy, Group from) { }\n    @Override\n    public void ccGroupMemberBanned(Action action, User banned, User bannedBy, Group from) { }\n});\n```\n\n### CometChatCallEvents\n\n```java\nCometChatCallEvents.addListener(\"unique-tag\", new CometChatCallEvents() {\n    @Override\n    public void ccOutgoingCall(Call call) { }\n    @Override\n    public void ccCallAccepted(Call call) { }\n    @Override\n    public void ccCallRejected(Call call) { }\n    @Override\n    public void ccCallEnded(Call call) { }\n});\n```\n\n---\n\n## 5. Custom view slots on components\n\nMost components support custom view injection via `Function3<Context, User, Group, View>`:\n\n```java\nCometChatMessageHeader header = findViewById(R.id.header);\nheader.setSubtitleView((context, user, group) -> {\n    TextView subtitle = new TextView(context);\n    if (user != null) {\n        subtitle.setText(user.getStatus().equals(\"online\") ? \"Active now\" : \"Offline\");\n    }\n    return subtitle;\n});\n```\n\n---\n\n## Hard rules\n\n- **Always extend `DataSourceDecorator`, never implement `DataSource` directly.** The decorator preserves existing behavior.\n- **Register `ChatConfigurator.enable()` AFTER `CometChatUIKit.init()` succeeds.** The configurator resets on init.\n- **Always remove event listeners when the Activity/Fragment is destroyed.** Use `onDestroy()` or `onDestroyView()`.\n- **Template view slots use `MessagesViewHolderListener`.** Implement both `createView()` and `bindView()`.","tags":["cometchat","android","customization","skills","agent-skills","ai-agent","chat","claude-code","cursor","messaging","nextjs","react"],"capabilities":["skill","source-cometchat","skill-cometchat-android-v5-customization","topic-agent-skills","topic-ai-agent","topic-chat","topic-claude-code","topic-cometchat","topic-cursor","topic-messaging","topic-nextjs","topic-react","topic-react-native","topic-ui-kit"],"categories":["cometchat-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/cometchat/cometchat-skills/cometchat-android-v5-customization","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add cometchat/cometchat-skills","source_repo":"https://github.com/cometchat/cometchat-skills","install_from":"skills.sh"}},"qualityScore":"0.463","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 27 github stars · SKILL.md body (9,836 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:04:44.817Z","embedding":null,"createdAt":"2026-05-07T13:05:03.612Z","updatedAt":"2026-05-18T19:04:44.817Z","lastSeenAt":"2026-05-18T19:04:44.817Z","tsv":"'1':137 '2':389 '3':418 '4':546 '5':750 'action':98,246,248,328,330,392,417,698,699,710,711 'activ':789 'activity/fragment':824 'ad':599,638 'add':86,95,441,480 'additionparamet':471,472,479,510,511,519 'align':181,205,284,304 'alway':796,818 'android':3,26,35,43,115,125,134 'appli':255 'architectur':49 'area':381 'arraylist':241 'avail':434 'ban':713 'bannedbi':715 'basemessag':202,228,303,323,467,468,477,506,507,517,577,578,618,619 'behavior':444,807 'beyond':9,59 'bind':212 'bindview':197,297,840 'bookmark':406,409,412,416 'bottomview':362 'bubbl':90,143,192,293,349,355,361,369,375,388 'bubbleview':344 'call':730,731,736,737,742,743,748,749 'catalog':32 'categori':152 'cccallaccept':735 'cccallend':747 'cccallreject':741 'ccgroupcreat':677 'ccgroupdelet':683 'ccgroupmemberban':709 'ccgroupmemberjoin':689 'ccgroupmemberkick':697 'ccmessages':576,617 'ccoutgoingcal':729 'ccuserblock':657 'ccuserunblock':663 'chang':110 'chat':556 'chatconfigur':71,532 'chatconfigurator.enable':535,542,809 'class':451,495,552 'click':252,334 'collections.singletonlist':260 'colors/fonts':111 'cometchat':2,7,25,34,42,57,114,124,133,549 'cometchat-android-v5-components':24 'cometchat-android-v5-core':132 'cometchat-android-v5-customization':1 'cometchat-android-v5-extensions':41 'cometchat-android-v5-features':123 'cometchat-android-v5-theming':33,113 'cometchatcallev':718,725 'cometchatcallevents.addlistener':720 'cometchatconstants.category':167,272 'cometchatconstants.message':163,268 'cometchatgroupev':666,673 'cometchatgroupevents.addgrouplistener':668 'cometchatmessagebubbl':178,283 'cometchatmessageev':564,572,614 'cometchatmessageevents.addlistener':567,609 'cometchatmessageevents.removelistener':603,642 'cometchatmessagehead':769 'cometchatmessageopt':244,326,390,402,405,485,522 'cometchatmessagetempl':138,158,161,266 'cometchatuikit.init':811 'cometchatuserev':646,653 'cometchatuserevents.adduserlistener':648 'companion':22 'compon':8,28,31,58,755,757 'configur':814 'content':367 'contentview':356 'context':176,177,188,198,199,227,280,281,289,298,299,322,465,466,476,504,505,516,764,774,781 'convers':103 'core':136 'cover':38,46,64 'createdview':201,300 'createdview.findviewbyid':220,314 'createview':175,279,838 'custom':5,6,11,19,56,65,75,82,88,97,154,184,216,231,245,247,250,327,329,332,391,481,751,759 'customdatasourc':452,456,496,538,544 'data':213 'datasourc':14,419,423,439,457,458,460,497,498,500,536,539,543,545,801 'datasource/datasourcedecorator':69 'datasourcedecor':421,435,454,499,798 'decor':15,804 'defin':140,425 'descript':343 'destroy':826 'direct':802 'done':602,641 'enabl':118 'entir':347 'equal':787 'event':16,72,94,547,551,557,820 'exist':438,806 'extend':453,797 'extens':45,48 'featur':121,127 'filter':102 'findviewbyid':771 'footerview':370 'fun':278,296,502,616,625,633 'function3':763 'gettext':225 'gettextmessageopt':464,503 'group':229,324,469,470,478,508,509,518,678,679,684,685,692,704,716,766,776 'handl':251,333,415 'hard':794 'header':770 'header.setsubtitleview':773 'headerview':350 'holder':207,306 'icon':413 'id':408 'implement':800,836 'inflat':189,290 'info':380 'init':817 'init/login':130 'inject':761 'insid':359,368 'int':210,311,579,621 'interfac':424 'java':156,157,400,401,448,449,533,534,565,566,647,667,719,768 'joinedgroup':693 'joinedus':691 'kick':701 'kickedbi':703 'kotlin':262,263,493,494,540,541,607,608 'layoutinflater.from':187,288 'list':85,208,238,258,309,463,473,512 'listen':17,73,91,559,821 'listof':325,336 'long':235,397 'long-press':234,396 'map':148 'menu':237,399 'messag':12,66,84,89,93,100,142,150,168,203,224,232,257,273,302,317,348,395,427,581,590,622,630 'messagebubbl':179,282 'messagelist':209,308 'messagelist.settemplates':259,335 'messagesviewholderlisten':171,276,346,352,358,364,372,378,384,835 'method':342 'modifi':443 'never':799 'new':160,170,240,243,404,484,537,571,652,672,724,779 'null':193,294,784 'object':275,613 'offlin':791 'onclick':414 'ondestroy':828 'ondestroyview':830 'onlin':788 'onmessagereactionad':595,634 'ontextmessagereceiv':586,626 'option':101,233,239,254,403,432,474,482,492,514,529 'options.add':242,483,521 'overrid':172,194,277,295,461,501,573,583,592,615,624,632,654,660,674,680,686,694,706,726,732,738,744 'packag':120 'pattern':70 'posit':211,310 'preserv':805 'press':236,398 'preview':386 'provid':29,62,550 'public':173,195,450,455,462,574,584,593,655,661,675,681,687,695,707,727,733,739,745 'purpos':50 'r.drawable.ic':249,331,411,488,525 'r.id.customtext':221,315 'r.id.header':772 'r.layout.custom':190,291 'react':554 'reaction':598,637 'reactionev':596,597,635,636 'receiv':591,631 'recyclerview.viewholder':206,307 'regist':530,558,808 'remov':600,639,819 'render':145,429 'replac':446 'repli':385 'replyview':382 'reset':815 'return':182,186,230,253,287,491,528,792 'rule':795 'sent':582,623 'set':128 'setbottomview':363 'setbubbleview':345 'setcategori':166,271 'setcontentview':169,274,357 'setfooterview':371 'setheaderview':351 'setopt':226,321 'setreplyview':383 'setstatusinfoview':377 'settyp':162,267 'skill':23,52,80,108 'skill-cometchat-android-v5-customization' 'slot':21,77,340,341,753,833 'source-cometchat' 'status':379,580,620 'statusinfoview':376 'style':40 'subtitl':778,793 'subtitle.settext':785 'succeed':812 'super':459 'super.gettextmessageoptions':475,515 'support':758 'system':548 'tag':563,570,606,612,645,651,671,723 'teach':53 'templat':13,67,139,147,159,261,265,337,338,831 'text':165,191,270,292,320,589,629 'textmessag':223,319,587,588,627,628 'textview':218,219,313,777,780 'textview.settext':222 'textview.text':316 'theme':10,37,61,117 'titl':410 'tomutablelist':520 'topic-agent-skills' 'topic-ai-agent' 'topic-chat' 'topic-claude-code' 'topic-cometchat' 'topic-cursor' 'topic-messaging' 'topic-nextjs' 'topic-react' 'topic-react-native' 'topic-ui-kit' 'translat':486,487,489,490,523,524,526,527 'type':151,164,269 'uikitconstants.messagebubblealignment':180,204,285,305 'uniqu':407,562,569,605,611,644,650,670,722 'unique-tag':568,604,610,643,649,669,721 'use':78,106,112,122,131,827,834 'user':658,659,664,665,690,700,702,712,714,765,775,783 'user.getstatus':786 'v5':4,27,36,44,116,126,135 'val':264,312,513 'via':531,762 'view':20,76,155,174,185,200,217,286,301,339,752,760,767,832 'visual':39 'void':196,575,585,594,656,662,676,682,688,696,708,728,734,740,746 'without':445 'wrap':436","prices":[{"id":"6a4effc2-f9d9-4732-b1ff-00b246da6d9a","listingId":"d972256b-ead4-4214-a587-3057d55eabf1","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"cometchat","category":"cometchat-skills","install_from":"skills.sh"},"createdAt":"2026-05-07T13:05:03.612Z"}],"sources":[{"listingId":"d972256b-ead4-4214-a587-3057d55eabf1","source":"github","sourceId":"cometchat/cometchat-skills/cometchat-android-v5-customization","sourceUrl":"https://github.com/cometchat/cometchat-skills/tree/main/skills/cometchat-android-v5-customization","isPrimary":false,"firstSeenAt":"2026-05-07T13:05:03.612Z","lastSeenAt":"2026-05-18T19:04:44.817Z"}],"details":{"listingId":"d972256b-ead4-4214-a587-3057d55eabf1","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"cometchat","slug":"cometchat-android-v5-customization","github":{"repo":"cometchat/cometchat-skills","stars":27,"topics":["agent-skills","ai-agent","chat","claude-code","cometchat","cursor","messaging","nextjs","react","react-native","ui-kit"],"license":null,"html_url":"https://github.com/cometchat/cometchat-skills","pushed_at":"2026-05-18T05:04:24Z","description":"Add CometChat chat to any React, Next.js, React Native, Angular, Android, iOS, or Flutter project through your AI coding agent. Works with Claude Code, Cursor, Codex, VS Code Copilot, Windsurf, Cline, Kiro, and 50+ more agents.","skill_md_sha":"06bca09ca9b43d006140512dc327507348a82eed","skill_md_path":"skills/cometchat-android-v5-customization/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/cometchat/cometchat-skills/tree/main/skills/cometchat-android-v5-customization"},"layout":"multi","source":"github","category":"cometchat-skills","frontmatter":{"name":"cometchat-android-v5-customization","license":"MIT","description":"Customize CometChat components beyond theming — custom message templates, DataSource decorators, event listeners, and custom view slots.","compatibility":"Android 7.0+; Java 8+; Kotlin 1.8+; com.cometchat:chat-uikit-android:5.x"},"skills_sh_url":"https://skills.sh/cometchat/cometchat-skills/cometchat-android-v5-customization"},"updatedAt":"2026-05-18T19:04:44.817Z"}}