After Width: | Height: | Size: 706 B |
After Width: | Height: | Size: 622 B |
After Width: | Height: | Size: 894 B |
After Width: | Height: | Size: 300 B |
After Width: | Height: | Size: 832 B |
After Width: | Height: | Size: 844 B |
After Width: | Height: | Size: 512 B |
After Width: | Height: | Size: 602 B |
After Width: | Height: | Size: 370 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 4.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 271 B |
After Width: | Height: | Size: 487 B |
After Width: | Height: | Size: 827 B |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 706 B |
After Width: | Height: | Size: 622 B |
After Width: | Height: | Size: 894 B |
After Width: | Height: | Size: 300 B |
After Width: | Height: | Size: 832 B |
After Width: | Height: | Size: 844 B |
After Width: | Height: | Size: 512 B |
After Width: | Height: | Size: 602 B |
After Width: | Height: | Size: 370 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 4.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 271 B |
After Width: | Height: | Size: 487 B |
After Width: | Height: | Size: 827 B |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 706 B |
After Width: | Height: | Size: 622 B |
After Width: | Height: | Size: 894 B |
After Width: | Height: | Size: 300 B |
After Width: | Height: | Size: 832 B |
After Width: | Height: | Size: 844 B |
After Width: | Height: | Size: 512 B |
After Width: | Height: | Size: 602 B |
After Width: | Height: | Size: 370 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 4.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 271 B |
After Width: | Height: | Size: 487 B |
After Width: | Height: | Size: 827 B |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 2.4 KiB |
@ -0,0 +1,198 @@
|
||||
// import 'package:emoji_picker_flutter/emoji_picker_flutter.dart';
|
||||
// import 'package:emoji_picker_flutter/src/category_emoji.dart';
|
||||
// import 'package:emoji_picker_flutter/src/config.dart';
|
||||
// import 'package:emoji_picker_flutter/src/emoji_picker_builder.dart';
|
||||
// import 'package:emoji_picker_flutter/src/emoji_view_state.dart';
|
||||
import 'package:bytedesk_kefu/vendors/emoji_picker_flutter/emoji_picker_flutter.dart';
|
||||
import 'package:bytedesk_kefu/vendors/emoji_picker_flutter/src/category_emoji.dart';
|
||||
// import 'package:bytedesk_kefu/vendors/emoji_picker_flutter/src/config.dart';
|
||||
// import 'package:bytedesk_kefu/vendors/emoji_picker_flutter/src/emoji_picker_builder.dart';
|
||||
// import 'package:bytedesk_kefu/vendors/emoji_picker_flutter/src/emoji_view_state.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// EmojiPicker Implementation
|
||||
class EmojiPickerView extends EmojiPickerBuilder {
|
||||
/// Constructor
|
||||
EmojiPickerView(
|
||||
Config config,
|
||||
EmojiViewState state,
|
||||
this.handleSendPressed,
|
||||
) : super(config, state);
|
||||
|
||||
@override
|
||||
_EmojiPickerViewState createState() => _EmojiPickerViewState();
|
||||
|
||||
/// See [AttachmentButton.onPressed]
|
||||
final void Function()? handleSendPressed;
|
||||
}
|
||||
|
||||
class _EmojiPickerViewState extends State<EmojiPickerView>
|
||||
with SingleTickerProviderStateMixin {
|
||||
PageController? _pageController;
|
||||
TabController? _tabController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
var initCategory = widget.state.categoryEmoji.indexWhere(
|
||||
(element) => element.category == widget.config.initCategory);
|
||||
if (initCategory == -1) {
|
||||
initCategory = 0;
|
||||
}
|
||||
_tabController = TabController(
|
||||
initialIndex: initCategory,
|
||||
length: widget.state.categoryEmoji.length,
|
||||
vsync: this);
|
||||
_pageController = PageController(initialPage: initCategory);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final emojiSize = widget.config.getEmojiSize(constraints.maxWidth);
|
||||
|
||||
return Container(
|
||||
color: Color.fromRGBO(251, 251, 251, 1.0), //widget.config.bgColor,
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TabBar(
|
||||
labelColor: widget.config.iconColorSelected,
|
||||
indicatorColor: widget.config.indicatorColor,
|
||||
unselectedLabelColor: widget.config.iconColor,
|
||||
controller: _tabController,
|
||||
labelPadding: EdgeInsets.zero,
|
||||
onTap: (index) {
|
||||
_pageController!.jumpToPage(index);
|
||||
},
|
||||
tabs: widget.state.categoryEmoji
|
||||
.asMap()
|
||||
.entries
|
||||
.map<Widget>((item) =>
|
||||
_buildCategory(item.key, item.value.category))
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
padding: const EdgeInsets.only(bottom: 2),
|
||||
icon: Icon(
|
||||
Icons.backspace,
|
||||
color: widget.config.backspaceColor,
|
||||
),
|
||||
onPressed: () {
|
||||
widget.state.onBackspacePressed!();
|
||||
},
|
||||
),
|
||||
// IconButton(
|
||||
// // iconSize: 16,
|
||||
// onPressed: () {
|
||||
// widget.handleSendPressed!();
|
||||
// },
|
||||
// // backgroundColor: Colors.lightGreen,
|
||||
// icon: Icon(Icons.send),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
Flexible(
|
||||
child: PageView.builder(
|
||||
itemCount: widget.state.categoryEmoji.length,
|
||||
controller: _pageController,
|
||||
onPageChanged: (index) {
|
||||
_tabController!.animateTo(
|
||||
index,
|
||||
duration: widget.config.tabIndicatorAnimDuration,
|
||||
);
|
||||
},
|
||||
itemBuilder: (context, index) =>
|
||||
_buildPage(emojiSize, widget.state.categoryEmoji[index]),
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCategory(int index, Category category) {
|
||||
return Tab(
|
||||
icon: Icon(
|
||||
widget.config.getIconForCategory(category),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildButtonWidget(
|
||||
{required VoidCallback onPressed, required Widget child}) {
|
||||
if (widget.config.buttonMode == ButtonMode.MATERIAL) {
|
||||
return TextButton(
|
||||
onPressed: onPressed,
|
||||
child: child,
|
||||
style: ButtonStyle(padding: MaterialStateProperty.all(EdgeInsets.zero)),
|
||||
);
|
||||
}
|
||||
return CupertinoButton(
|
||||
padding: EdgeInsets.zero, onPressed: onPressed, child: child);
|
||||
}
|
||||
|
||||
Widget _buildPage(double emojiSize, CategoryEmoji categoryEmoji) {
|
||||
// Display notice if recent has no entries yet
|
||||
if (categoryEmoji.category == Category.RECENT &&
|
||||
categoryEmoji.emoji.isEmpty) {
|
||||
return _buildNoRecent();
|
||||
}
|
||||
// Build page normally
|
||||
return GridView.count(
|
||||
scrollDirection: Axis.vertical,
|
||||
physics: const ScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
primary: true,
|
||||
padding: const EdgeInsets.all(0),
|
||||
crossAxisCount: widget.config.columns,
|
||||
mainAxisSpacing: widget.config.verticalSpacing,
|
||||
crossAxisSpacing: widget.config.horizontalSpacing,
|
||||
children: categoryEmoji.emoji
|
||||
.map<Widget>((item) => _buildEmoji(emojiSize, categoryEmoji, item))
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildEmoji(
|
||||
double emojiSize,
|
||||
CategoryEmoji categoryEmoji,
|
||||
Emoji emoji,
|
||||
) {
|
||||
return _buildButtonWidget(
|
||||
onPressed: () {
|
||||
widget.state.onEmojiSelected(categoryEmoji.category, emoji);
|
||||
},
|
||||
child: FittedBox(
|
||||
fit: BoxFit.fill,
|
||||
child: Text(
|
||||
emoji.emoji,
|
||||
textScaleFactor: 1.0,
|
||||
style: TextStyle(
|
||||
fontSize: emojiSize,
|
||||
backgroundColor: Colors.transparent,
|
||||
),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
Widget _buildNoRecent() {
|
||||
return Center(
|
||||
child: Text( '无最近使用表情',
|
||||
// widget.config.noRecentsText,
|
||||
// style: widget.config.noRecentsStyle,
|
||||
textAlign: TextAlign.center,
|
||||
));
|
||||
}
|
||||
}
|
@ -0,0 +1,297 @@
|
||||
import 'package:carousel_slider/carousel_slider.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
// import 'package:flutter/widgets.dart';
|
||||
// import 'package:get/get.dart';
|
||||
// import 'package:get/get_utils/src/extensions/internacionalization.dart';
|
||||
// import 'package:imboy/config/const.dart';
|
||||
|
||||
class ExtraItem extends StatelessWidget {
|
||||
const ExtraItem({
|
||||
Key? key,
|
||||
required this.onPressed,
|
||||
required this.image,
|
||||
double? this.width,
|
||||
double? this.height,
|
||||
required this.title,
|
||||
}) : super(key: key);
|
||||
|
||||
final ImageProvider image;
|
||||
final void Function()? onPressed;
|
||||
final double? width;
|
||||
final double? height;
|
||||
final String title;
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: this.onPressed ?? () => {
|
||||
print('功能暂未实现')
|
||||
},
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(left: 15, top: 13, right: 15, bottom: 0),
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
width: this.width ?? 56,
|
||||
height: this.height ?? 56,
|
||||
// margin: EdgeInsets.symmetric(horizontal: 10),
|
||||
child: Material(
|
||||
color: AppColors.ChatInputBackgroundColor,
|
||||
// INK可以实现装饰容器
|
||||
child: new Ink(
|
||||
// 用ink圆角矩形
|
||||
decoration: BoxDecoration(
|
||||
// 背景
|
||||
color: AppColors.ChatInputBackgroundColor,
|
||||
// 设置四周圆角 角度
|
||||
borderRadius: BorderRadius.all(Radius.circular(16.0)),
|
||||
// 设置四周边框
|
||||
border: Border.all(
|
||||
width: 1,
|
||||
color: AppColors.ChatInputBackgroundColor,
|
||||
),
|
||||
),
|
||||
child: Image(
|
||||
image: this.image,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(this.title),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ExtraItems extends StatefulWidget {
|
||||
const ExtraItems({
|
||||
Key? key,
|
||||
this.handleImageSelection,
|
||||
this.handleFileSelection,
|
||||
this.handlePickerSelection,
|
||||
this.handleUploadVideo,
|
||||
this.handleCaptureVideo,
|
||||
}) : super(key: key);
|
||||
|
||||
final void Function()? handleImageSelection;
|
||||
final void Function()? handleFileSelection;
|
||||
final void Function()? handlePickerSelection;
|
||||
final void Function()? handleUploadVideo;
|
||||
final void Function()? handleCaptureVideo;
|
||||
|
||||
@override
|
||||
_ExtraItemsState createState() => _ExtraItemsState();
|
||||
}
|
||||
|
||||
class _ExtraItemsState extends State<ExtraItems> {
|
||||
int _current = 0;
|
||||
CarouselController _controller = CarouselController();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var items = [
|
||||
Column(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: [
|
||||
ExtraItem(
|
||||
title: "照片",
|
||||
image: AssetImage('assets/images/chat/extra_photo.webp'),
|
||||
onPressed: widget.handleImageSelection,
|
||||
),
|
||||
ExtraItem(
|
||||
title: "拍摄",
|
||||
image: AssetImage('assets/images/chat/extra_camera.webp'),
|
||||
onPressed: widget.handlePickerSelection,
|
||||
),
|
||||
ExtraItem(
|
||||
title: "上传视频",
|
||||
image: AssetImage('assets/images/chat/extra_media.webp'),
|
||||
onPressed: widget.handleUploadVideo,
|
||||
),
|
||||
ExtraItem(
|
||||
title: "录制视频",
|
||||
image: AssetImage('assets/images/chat/extra_videocall.webp'),
|
||||
onPressed: widget.handleCaptureVideo,
|
||||
),
|
||||
// ExtraItem(
|
||||
// title: "位置",
|
||||
// image: AssetImage('assets/images/chat/extra_localtion.webp'),
|
||||
// onPressed: null,
|
||||
// ),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
// TODO: 选择文件
|
||||
// ExtraItem(
|
||||
// title: "文件",
|
||||
// image: AssetImage('assets/images/chat/extra_file.webp'),
|
||||
// onPressed: widget.handleFileSelection,
|
||||
// ),
|
||||
// ExtraItem(
|
||||
// title: "语音输入",
|
||||
// image: AssetImage('assets/images/chat/extra_voice.webp'),
|
||||
// onPressed: null,
|
||||
// ),
|
||||
// ExtraItem(
|
||||
// title: "收藏",
|
||||
// image: AssetImage('assets/images/chat/extra_favorite.webp'),
|
||||
// onPressed: null,
|
||||
// ),
|
||||
// ExtraItem(
|
||||
// title: "个人名片",
|
||||
// image: AssetImage('assets/images/chat/extra_card.webp'),
|
||||
// onPressed: null,
|
||||
// ),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
// Column(
|
||||
// children: <Widget>[
|
||||
// Row(children: [
|
||||
// ExtraItem(
|
||||
// title: "文件",
|
||||
// image: AssetImage('assets/images/chat/extra_file.webp'),
|
||||
// onPressed: widget.handleFileSelection,
|
||||
// ),
|
||||
// ExtraItem(
|
||||
// title: "卡券",
|
||||
// image: AssetImage('assets/images/chat/extra_wallet.png'),
|
||||
// onPressed: null,
|
||||
// ),
|
||||
// ]),
|
||||
// ],
|
||||
// ),
|
||||
];
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: CarouselSlider(
|
||||
options: CarouselOptions(
|
||||
height: 50, // Get.height,
|
||||
viewportFraction: 1.0,
|
||||
aspectRatio: 2.0,
|
||||
scrollDirection: Axis.horizontal,
|
||||
disableCenter: true,
|
||||
initialPage: 1,
|
||||
enableInfiniteScroll: false,
|
||||
onPageChanged: (index, reason) {
|
||||
setState(() {
|
||||
_current = index;
|
||||
});
|
||||
},
|
||||
),
|
||||
items: items.map((tab) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(left: 8),
|
||||
child: tab,
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: items.asMap().entries.map((entry) {
|
||||
return GestureDetector(
|
||||
onTap: () => _controller.animateToPage(entry.key),
|
||||
child: Container(
|
||||
width: 10.0,
|
||||
height: 10.0,
|
||||
margin: EdgeInsets.symmetric(
|
||||
vertical: 8.0,
|
||||
horizontal: 6.0,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: (Theme.of(context).brightness == Brightness.dark
|
||||
? Colors.white
|
||||
: Colors.black)
|
||||
.withOpacity(_current == entry.key ? 0.7 : 0.2),
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AppColors {
|
||||
static const AppBarColor = Color.fromRGBO(237, 237, 237, 1);
|
||||
|
||||
static const BgColor = Color.fromRGBO(255, 255, 255, 1);
|
||||
|
||||
static const LineColor = Colors.grey;
|
||||
|
||||
static const TipColor = Color.fromRGBO(89, 96, 115, 1.0);
|
||||
|
||||
static const MainTextColor = Color.fromRGBO(115, 115, 115, 1.0);
|
||||
|
||||
static const LabelTextColor = Color.fromRGBO(144, 144, 144, 1.0);
|
||||
|
||||
static const ItemBgColor = Color.fromRGBO(75, 75, 75, 1.0);
|
||||
|
||||
static const ItemOnColor = Color.fromRGBO(68, 68, 68, 1.0);
|
||||
|
||||
static const ButtonTextColor = Color.fromRGBO(112, 113, 135, 1.0);
|
||||
|
||||
static const TitleColor = 0xff181818;
|
||||
static const ButtonArrowColor = 0xffadadad;
|
||||
|
||||
///
|
||||
|
||||
/// 主背景 白色
|
||||
static const Color primaryBackground = Color.fromARGB(255, 255, 255, 255);
|
||||
|
||||
/// 主文本 灰色
|
||||
static const Color primaryText = Color.fromARGB(255, 45, 45, 47);
|
||||
|
||||
/// 主控件-背景 绿色
|
||||
static const Color primaryElement = Color.fromARGB(255, 109, 192, 102);
|
||||
|
||||
/// 主控件-文本 白色
|
||||
static const Color primaryElementText = Color.fromARGB(255, 255, 255, 255);
|
||||
|
||||
// *****************************************
|
||||
|
||||
/// 第二种控件-背景色 淡灰色
|
||||
static const Color secondaryElement = Color.fromARGB(255, 246, 246, 246);
|
||||
|
||||
/// 第二种控件-文本 浅绿色
|
||||
static const Color secondaryElementText = Color.fromRGBO(169, 234, 122, 1.0);
|
||||
|
||||
// *****************************************
|
||||
|
||||
/// 第三种控件-背景色 石墨色
|
||||
static const Color thirdElement = Color.fromARGB(255, 45, 45, 47);
|
||||
|
||||
/// 第三种控件-文本 浅灰色2
|
||||
static const Color thirdElementText = Color.fromARGB(255, 141, 141, 142);
|
||||
|
||||
// *****************************************
|
||||
|
||||
/// tabBar 默认颜色 灰色
|
||||
static const Color tabBarElement = Color.fromARGB(255, 208, 208, 208);
|
||||
|
||||
/// tabCellSeparator 单元格底部分隔条 颜色
|
||||
static const Color tabCellSeparator = Color.fromARGB(255, 230, 230, 231);
|
||||
|
||||
// for chat
|
||||
static const ChatBg = Color.fromRGBO(243, 243, 243, 1.0);
|
||||
static const ChatSendMessgeBgColor = Color.fromRGBO(169, 234, 122, 1.0);
|
||||
static const ChatSentMessageBodyTextColor = Color.fromRGBO(19, 29, 13, 1.0);
|
||||
|
||||
static const ChatReceivedMessageBodyTextColor =
|
||||
Color.fromRGBO(25, 25, 25, 1.0);
|
||||
static const ChatReceivedMessageBodyBgColor =
|
||||
Color.fromRGBO(255, 255, 255, 1.0);
|
||||
static const ChatInputBackgroundColor = Color.fromRGBO(240, 240, 240, 1.0);
|
||||
static const ChatInputFillGgColor = Color.fromRGBO(251, 251, 251, 1.0);
|
||||
// end for chat
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ImageButton extends StatefulWidget {
|
||||
const ImageButton({
|
||||
Key? key,
|
||||
required this.onPressed,
|
||||
required this.image,
|
||||
double? this.width,
|
||||
double? this.height,
|
||||
String? this.title,
|
||||
}) : super(key: key);
|
||||
|
||||
final ImageProvider image;
|
||||
final void Function()? onPressed;
|
||||
final double? width;
|
||||
final double? height;
|
||||
final String? title;
|
||||
|
||||
@override
|
||||
_ImageButtonState createState() => _ImageButtonState();
|
||||
}
|
||||
|
||||
class _ImageButtonState extends State<ImageButton> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: widget.onPressed,
|
||||
child: Container(
|
||||
width: widget.width ?? 44,
|
||||
height: widget.height ?? 44,
|
||||
alignment: Alignment.center,
|
||||
child: Image(
|
||||
image: widget.image,
|
||||
width: widget.width ?? 35,
|
||||
height: widget.height ?? 35,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
/// Used to toggle the visibility behavior of the [SendButton] based on the
|
||||
/// [TextField] state inside the [Input] widget.
|
||||
enum SendButtonVisibilityMode {
|
||||
/// Always show the [SendButton] regardless of the [TextField] state.
|
||||
always,
|
||||
|
||||
/// The [SendButton] will only appear when the [TextField] is not empty.
|
||||
editing,
|
||||
|
||||
/// Always hide the [SendButton] regardless of the [TextField] state.
|
||||
hidden,
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class CustomOverlay extends StatelessWidget {
|
||||
final Widget? icon;
|
||||
final BoxDecoration decoration;
|
||||
final double width;
|
||||
final double height;
|
||||
|
||||
const CustomOverlay({
|
||||
Key? key,
|
||||
this.icon,
|
||||
this.decoration = const BoxDecoration(
|
||||
color: Color(0xff77797A),
|
||||
borderRadius: BorderRadius.all(Radius.circular(20.0)),
|
||||
),
|
||||
this.width = 160,
|
||||
this.height = 160,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Positioned(
|
||||
top: MediaQuery.of(context).size.height * 0.5 - width / 2,
|
||||
left: MediaQuery.of(context).size.width * 0.5 - height / 2,
|
||||
child: Material(
|
||||
type: MaterialType.transparency,
|
||||
child: Center(
|
||||
child: Opacity(
|
||||
opacity: 0.8,
|
||||
child: Container(
|
||||
width: width,
|
||||
height: height,
|
||||
decoration: decoration,
|
||||
child: icon,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
library emoji_picker_flutter;
|
||||
|
||||
export './src/category_icons.dart';
|
||||
export './src/config.dart';
|
||||
export './src/emoji.dart';
|
||||
export './src/emoji_picker.dart';
|
||||
export './src/emoji_picker_builder.dart';
|
||||
export './src/emoji_picker_utils.dart';
|
||||
export './src/emoji_view_state.dart';
|
@ -0,0 +1,13 @@
|
||||
import '../emoji_picker_flutter.dart';
|
||||
|
||||
/// Container for Category and their emoji
|
||||
class CategoryEmoji {
|
||||
/// Constructor
|
||||
CategoryEmoji(this.category, this.emoji);
|
||||
|
||||
/// Category instance
|
||||
final Category category;
|
||||
|
||||
/// List of emoji of this category
|
||||
List<Emoji> emoji;
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Class that defines the icon representing a [Category]
|
||||
class CategoryIcon {
|
||||
/// Icon of Category
|
||||
const CategoryIcon({
|
||||
required this.icon,
|
||||
this.color = const Color.fromRGBO(211, 211, 211, 1),
|
||||
this.selectedColor = const Color.fromRGBO(178, 178, 178, 1),
|
||||
});
|
||||
|
||||
/// The icon to represent the category
|
||||
final IconData icon;
|
||||
|
||||
/// The default color of the icon
|
||||
final Color color;
|
||||
|
||||
/// The color of the icon once the category is selected
|
||||
final Color selectedColor;
|
||||
}
|