The BuilderSettingsHelper handles basic feature toggles. For deeper customizations, modify the configuration JSON, theme settings, or component props directly.
Understanding the Customization Architecture
The Flutter UI Kit Builder uses these main files for customization:
| File | Purpose | When to Modify |
|---|
cometchat-builder-settings.json | Feature flags and configuration constants | Functional changes (enable/disable features) |
BuilderSettingsHelper | Utility class for loading and accessing settings | Runtime configuration access |
pubspec.yaml | Font and asset declarations | Adding custom fonts or assets |
The cometchat-builder-settings.json file is the source of truth for your Builder configuration. Update it and reload to apply changes.
Using BuilderSettingsHelper
The BuilderSettingsHelper provides access to your Builder configuration throughout your app.
Loading Configuration
import 'package:chat_builder/utils/builder_settings_helper.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// Load settings from assets
await BuilderSettingsHelper.loadFromAsset();
runApp(const MyApp());
}
Accessing Settings
import 'package:chat_builder/utils/builder_settings_helper.dart';
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final settings = BuilderSettingsHelper.settings;
// Access chat features
final chatFeatures = settings.chatFeatures;
final isPhotosEnabled = chatFeatures.coreMessagingExperience.photosSharing;
// Access style settings
final style = settings.style;
final brandColor = style.color.brandColor;
// Access layout settings
final layout = settings.layout;
final tabs = layout.tabs;
return Container(/* ... */);
}
}
Theme Customization
Applying Builder Theme to UI Kit
Apply the Builder configuration colors to your Flutter theme:
import 'package:flutter/material.dart';
import 'package:chat_builder/utils/builder_settings_helper.dart';
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
final style = BuilderSettingsHelper.settings.style;
return MaterialApp(
theme: ThemeData(
primaryColor: Color(int.parse(style.color.brandColor.replaceFirst('#', '0xFF'))),
colorScheme: ColorScheme.light(
primary: Color(int.parse(style.color.brandColor.replaceFirst('#', '0xFF'))),
),
textTheme: TextTheme(
bodyLarge: TextStyle(
color: Color(int.parse(style.color.primaryTextLight.replaceFirst('#', '0xFF'))),
),
bodyMedium: TextStyle(
color: Color(int.parse(style.color.secondaryTextLight.replaceFirst('#', '0xFF'))),
),
),
fontFamily: style.typography.font,
),
darkTheme: ThemeData.dark().copyWith(
primaryColor: Color(int.parse(style.color.brandColor.replaceFirst('#', '0xFF'))),
colorScheme: ColorScheme.dark(
primary: Color(int.parse(style.color.brandColor.replaceFirst('#', '0xFF'))),
),
textTheme: TextTheme(
bodyLarge: TextStyle(
color: Color(int.parse(style.color.primaryTextDark.replaceFirst('#', '0xFF'))),
),
bodyMedium: TextStyle(
color: Color(int.parse(style.color.secondaryTextDark.replaceFirst('#', '0xFF'))),
),
),
fontFamily: style.typography.font,
),
themeMode: _getThemeMode(style.theme),
home: HomeScreen(),
);
}
ThemeMode _getThemeMode(String theme) {
switch (theme) {
case 'light':
return ThemeMode.light;
case 'dark':
return ThemeMode.dark;
default:
return ThemeMode.system;
}
}
}
Custom Color Utilities
Create a utility class for working with Builder colors:
import 'package:flutter/material.dart';
import 'package:chat_builder/utils/builder_settings_helper.dart';
class BuilderColors {
static Color get brandColor {
final hex = BuilderSettingsHelper.settings.style.color.brandColor;
return _hexToColor(hex);
}
static Color get primaryTextLight {
final hex = BuilderSettingsHelper.settings.style.color.primaryTextLight;
return _hexToColor(hex);
}
static Color get primaryTextDark {
final hex = BuilderSettingsHelper.settings.style.color.primaryTextDark;
return _hexToColor(hex);
}
static Color get secondaryTextLight {
final hex = BuilderSettingsHelper.settings.style.color.secondaryTextLight;
return _hexToColor(hex);
}
static Color get secondaryTextDark {
final hex = BuilderSettingsHelper.settings.style.color.secondaryTextDark;
return _hexToColor(hex);
}
static Color _hexToColor(String hex) {
return Color(int.parse(hex.replaceFirst('#', '0xFF')));
}
}
Custom Font Integration
Step 1: Add Font Files
Add your custom font files to the assets/fonts/ directory.
Step 2: Update pubspec.yaml
Register your custom fonts:
flutter:
fonts:
- family: YourCustomFont
fonts:
- asset: assets/fonts/your_font_regular.ttf
- asset: assets/fonts/your_font_medium.ttf
weight: 500
- asset: assets/fonts/your_font_bold.ttf
weight: 700
Step 3: Apply Custom Font
Update the configuration JSON or apply programmatically:
// In your theme configuration
ThemeData(
fontFamily: 'YourCustomFont',
// ... other theme settings
)
Component-Level Customizations
Conditional Rendering Based on Features
Use the configuration to conditionally render UI elements:
import 'package:chat_builder/utils/builder_settings_helper.dart';
class MessageComposer extends StatelessWidget {
@override
Widget build(BuildContext context) {
final chatFeatures = BuilderSettingsHelper.settings.chatFeatures;
final core = chatFeatures.coreMessagingExperience;
final engagement = chatFeatures.deeperUserEngagement;
return Row(
children: [
// Always show text input
Expanded(child: TextField()),
// Conditionally show attachment options
if (core.photosSharing)
IconButton(
icon: Icon(Icons.photo),
onPressed: () => _attachPhoto(),
),
if (core.fileSharing)
IconButton(
icon: Icon(Icons.attach_file),
onPressed: () => _attachFile(),
),
if (engagement.voiceNotes)
IconButton(
icon: Icon(Icons.mic),
onPressed: () => _recordVoiceNote(),
),
if (engagement.stickers)
IconButton(
icon: Icon(Icons.emoji_emotions),
onPressed: () => _showStickers(),
),
],
);
}
}
Customizing Message Options
Control which message options appear based on configuration:
class MessageOptionsSheet extends StatelessWidget {
final Message message;
const MessageOptionsSheet({required this.message});
@override
Widget build(BuildContext context) {
final chatFeatures = BuilderSettingsHelper.settings.chatFeatures;
final core = chatFeatures.coreMessagingExperience;
final engagement = chatFeatures.deeperUserEngagement;
final moderator = chatFeatures.moderatorControls;
return Column(
mainAxisSize: MainAxisSize.min,
children: [
if (core.quotedReplies)
ListTile(
leading: Icon(Icons.reply),
title: Text('Reply'),
onTap: () => _handleReply(),
),
if (core.threadConversationAndReplies)
ListTile(
leading: Icon(Icons.forum),
title: Text('Reply in Thread'),
onTap: () => _handleThreadReply(),
),
if (engagement.reactions)
ListTile(
leading: Icon(Icons.add_reaction),
title: Text('React'),
onTap: () => _handleReaction(),
),
if (core.editMessage && _isOwnMessage())
ListTile(
leading: Icon(Icons.edit),
title: Text('Edit'),
onTap: () => _handleEdit(),
),
if (core.deleteMessage && _isOwnMessage())
ListTile(
leading: Icon(Icons.delete),
title: Text('Delete'),
onTap: () => _handleDelete(),
),
if (moderator.reportMessage)
ListTile(
leading: Icon(Icons.flag),
title: Text('Report'),
onTap: () => _handleReport(),
),
],
);
}
}
Layout Customization
Dynamic Tab Configuration
import 'package:chat_builder/utils/builder_settings_helper.dart';
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final layout = BuilderSettingsHelper.settings.layout;
if (!layout.withSideBar) {
return SingleChatView();
}
final tabs = layout.tabs;
return DefaultTabController(
length: tabs.length,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
tabs: [
if (tabs.contains('chats'))
Tab(icon: Icon(Icons.chat), text: 'Chats'),
if (tabs.contains('calls'))
Tab(icon: Icon(Icons.call), text: 'Calls'),
if (tabs.contains('users'))
Tab(icon: Icon(Icons.people), text: 'Users'),
if (tabs.contains('groups'))
Tab(icon: Icon(Icons.group), text: 'Groups'),
],
),
),
body: TabBarView(
children: [
if (tabs.contains('chats')) ChatsScreen(),
if (tabs.contains('calls')) CallsScreen(),
if (tabs.contains('users')) UsersScreen(),
if (tabs.contains('groups')) GroupsScreen(),
],
),
),
);
}
}
Call Features Customization
class ChatHeader extends StatelessWidget {
final bool isGroup;
const ChatHeader({required this.isGroup});
@override
Widget build(BuildContext context) {
final callFeatures = BuilderSettingsHelper.settings.callFeatures;
final calling = callFeatures.voiceAndVideoCalling;
return AppBar(
actions: [
if (isGroup) ...[
if (calling.groupVoiceConference)
IconButton(
icon: Icon(Icons.call),
onPressed: () => _startGroupVoiceCall(),
),
if (calling.groupVideoConference)
IconButton(
icon: Icon(Icons.videocam),
onPressed: () => _startGroupVideoCall(),
),
] else ...[
if (calling.oneOnOneVoiceCalling)
IconButton(
icon: Icon(Icons.call),
onPressed: () => _startVoiceCall(),
),
if (calling.oneOnOneVideoCalling)
IconButton(
icon: Icon(Icons.videocam),
onPressed: () => _startVideoCall(),
),
],
],
);
}
}
Reloading Configuration
Refresh Settings at Runtime
import 'package:chat_builder/utils/builder_settings_helper.dart';
class SettingsScreen extends StatelessWidget {
Future<void> _reloadConfiguration() async {
// Reload from assets
await BuilderSettingsHelper.loadFromAsset();
// Trigger UI rebuild
// Use a state management solution to notify listeners
}
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: _reloadConfiguration,
child: Text('Reload Configuration'),
);
}
}