mirror of
https://github.com/foss42/apidash.git
synced 2025-12-03 11:27:50 +08:00
add multi_trigger_autocomplete_plus
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
import 'package:example/src/models.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_parsed_text/flutter_parsed_text.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
|
||||
class ChatMessageList extends StatelessWidget {
|
||||
const ChatMessageList({
|
||||
Key? key,
|
||||
required this.messages,
|
||||
}) : super(key: key);
|
||||
|
||||
final List<ChatMessage> messages;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final messages = this.messages.reversed.toList();
|
||||
return ListView.separated(
|
||||
reverse: true,
|
||||
itemCount: messages.length,
|
||||
padding: const EdgeInsets.all(8),
|
||||
separatorBuilder: (context, index) => const SizedBox(height: 8),
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final message = messages[index];
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFFE9EAF4),
|
||||
borderRadius: BorderRadius.only(
|
||||
topRight: Radius.circular(32.0),
|
||||
topLeft: Radius.circular(32.0),
|
||||
bottomLeft: Radius.circular(32.0),
|
||||
),
|
||||
),
|
||||
child: ParsedText(
|
||||
text: message.text,
|
||||
style: GoogleFonts.robotoMono(
|
||||
fontWeight: FontWeight.w500,
|
||||
color: const Color(0xFF79708F),
|
||||
),
|
||||
parse: <MatchText>[
|
||||
MatchText(
|
||||
pattern: r"@[A-Za-z0-9_.-]*",
|
||||
style: const TextStyle(color: Colors.green),
|
||||
),
|
||||
MatchText(
|
||||
pattern: r"\B#+([\w]+)\b",
|
||||
style: const TextStyle(color: Colors.blue),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
CircleAvatar(
|
||||
backgroundImage: NetworkImage(message.sender.avatar),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import 'package:example/src/models.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'dart:math' show Random;
|
||||
|
||||
import 'package:example/src/data.dart';
|
||||
|
||||
class ChatMessageTextField extends StatelessWidget {
|
||||
const ChatMessageTextField({
|
||||
Key? key,
|
||||
required this.focusNode,
|
||||
required this.controller,
|
||||
required this.onSend,
|
||||
}) : super(key: key);
|
||||
|
||||
final FocusNode focusNode;
|
||||
final TextEditingController controller;
|
||||
final ValueSetter<ChatMessage> onSend;
|
||||
|
||||
final _sender = const [sahil, avni, gaurav];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.fromLTRB(16, 4, 4, 4),
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFFF7F7F8),
|
||||
borderRadius: BorderRadius.all(Radius.circular(40.0)),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextField(
|
||||
focusNode: focusNode,
|
||||
controller: controller,
|
||||
decoration: const InputDecoration.collapsed(
|
||||
hintText: "Type your message...",
|
||||
),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
final message = ChatMessage(
|
||||
text: controller.text,
|
||||
createdAt: DateTime.now(),
|
||||
sender: _sender[Random().nextInt(_sender.length)],
|
||||
);
|
||||
onSend(message);
|
||||
},
|
||||
padding: const EdgeInsets.all(4),
|
||||
icon: Container(
|
||||
decoration: const BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Color(0xFF5B61B9),
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: const Icon(
|
||||
Icons.send_rounded,
|
||||
color: Colors.white,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
import 'package:example/src/models.dart';
|
||||
|
||||
const sahil = User(
|
||||
id: 'xsahil03x',
|
||||
name: 'Sahil Kumar',
|
||||
avatar: 'https://bit.ly/3yEVRrD',
|
||||
);
|
||||
|
||||
const avni = User(
|
||||
id: 'avu.saxena',
|
||||
name: 'Avni Saxena',
|
||||
avatar: 'https://bit.ly/3PbPBii',
|
||||
);
|
||||
|
||||
const trapti = User(
|
||||
id: 'trapti2711',
|
||||
name: 'Trapti Gupta',
|
||||
avatar: 'https://bit.ly/3aDHtba',
|
||||
);
|
||||
|
||||
const gaurav = User(
|
||||
id: 'itsmegb98',
|
||||
name: 'Gaurav Bhadouriya',
|
||||
avatar: 'https://bit.ly/3PmNdES',
|
||||
);
|
||||
|
||||
const amit = User(
|
||||
id: 'amitk_15',
|
||||
name: 'Amit Kumar',
|
||||
avatar: 'https://bit.ly/3P9GPB8',
|
||||
);
|
||||
|
||||
const ayush = User(
|
||||
id: 'ayushpgupta',
|
||||
name: 'Ayush Gupta',
|
||||
avatar: 'https://bit.ly/3Rw61Dv',
|
||||
);
|
||||
|
||||
const shubham = User(
|
||||
id: 'someshubham',
|
||||
name: 'Shubham Jain',
|
||||
avatar: 'https://bit.ly/3Rs3uud',
|
||||
);
|
||||
|
||||
const kUsers = <User>[
|
||||
sahil,
|
||||
avni,
|
||||
gaurav,
|
||||
trapti,
|
||||
amit,
|
||||
ayush,
|
||||
shubham,
|
||||
];
|
||||
|
||||
const kHashtags = <Hashtag>[
|
||||
Hashtag(
|
||||
name: 'dart',
|
||||
weight: 1,
|
||||
description:
|
||||
'Dart is a language for building fast, scalable and maintainable applications.',
|
||||
image: 'https://dwglogo.com/wp-content/uploads/2018/03/Dart_logo.png',
|
||||
),
|
||||
Hashtag(
|
||||
name: 'flutter',
|
||||
weight: 2,
|
||||
description:
|
||||
'Flutter is a framework for building native Android and iOS applications for Google\'s mobile platforms.',
|
||||
image:
|
||||
'https://storage.googleapis.com/cms-storage-bucket/0dbfcc7a59cd1cf16282.png',
|
||||
),
|
||||
Hashtag(
|
||||
name: 'firebase',
|
||||
weight: 3,
|
||||
description:
|
||||
'Firebase is a cloud platform for building mobile and web apps.',
|
||||
image:
|
||||
'https://firebase.google.com/static/downloads/brand-guidelines/PNG/logo-logomark.png',
|
||||
),
|
||||
Hashtag(
|
||||
name: 'google',
|
||||
weight: 4,
|
||||
description:
|
||||
'Google is a company that builds products and services for the world\'s users.',
|
||||
image: 'https://dwglogo.com/wp-content/uploads/2016/06/G-icon-1068x735.png',
|
||||
),
|
||||
Hashtag(
|
||||
name: 'apple',
|
||||
weight: 5,
|
||||
description:
|
||||
'Apple is a company that builds products and services for the world\'s users.',
|
||||
image:
|
||||
'https://dwglogo.com/wp-content/uploads/2016/02/Apple_logo-1068x601.png',
|
||||
),
|
||||
Hashtag(
|
||||
name: 'microsoft',
|
||||
weight: 6,
|
||||
description:
|
||||
'Microsoft is a company that builds products and services for the world\'s users.',
|
||||
image:
|
||||
'https://upload.wikimedia.org/wikipedia/commons/thumb/4/44/Microsoft_logo.svg/2048px-Microsoft_logo.svg.png',
|
||||
),
|
||||
Hashtag(
|
||||
name: 'facebook',
|
||||
weight: 7,
|
||||
description:
|
||||
'Facebook is a company that builds products and services for the world\'s users.',
|
||||
image: 'https://www.facebook.com/images/fb_icon_325x325.png',
|
||||
),
|
||||
Hashtag(
|
||||
name: 'twitter',
|
||||
weight: 8,
|
||||
description:
|
||||
'Twitter is a company that builds products and services for the world\'s users.',
|
||||
image:
|
||||
'https://dwglogo.com/wp-content/uploads/2019/02/Twitter_logo-1024x705.png',
|
||||
),
|
||||
Hashtag(
|
||||
name: 'instagram',
|
||||
weight: 9,
|
||||
description:
|
||||
'Instagram is a company that builds products and services for the world\'s users.',
|
||||
image:
|
||||
'https://w7.pngwing.com/pngs/648/943/png-transparent-instagram-logo-logo-instagram-computer-icons-camera-instagram-logo-text-trademark-magenta.png',
|
||||
),
|
||||
Hashtag(
|
||||
name: 'snapchat',
|
||||
weight: 10,
|
||||
description:
|
||||
'Snapchat is a company that builds products and services for the world\'s users.',
|
||||
image:
|
||||
'https://dwglogo.com/wp-content/uploads/2016/06/dotted_logo_of_snapchat-1068x601.png',
|
||||
),
|
||||
Hashtag(
|
||||
name: 'youtube',
|
||||
weight: 11,
|
||||
description:
|
||||
'YouTube is a company that builds products and services for the world\'s users.',
|
||||
image:
|
||||
'https://dwglogo.com/wp-content/uploads/2020/05/1200px-YouTube_logo-1024x729.png',
|
||||
),
|
||||
];
|
||||
|
||||
const kEmojis = <Emoji>[
|
||||
Emoji(
|
||||
char: '😀',
|
||||
shortName: ':grinning:',
|
||||
unicode: '1f600',
|
||||
),
|
||||
Emoji(
|
||||
char: '😂',
|
||||
shortName: ':joy:',
|
||||
unicode: '1f602',
|
||||
),
|
||||
Emoji(
|
||||
char: '😃',
|
||||
shortName: ':smiley:',
|
||||
unicode: '1f603',
|
||||
),
|
||||
Emoji(
|
||||
char: '😄',
|
||||
shortName: ':smile:',
|
||||
unicode: '1f604',
|
||||
),
|
||||
Emoji(
|
||||
char: '😅',
|
||||
shortName: ':sweat_smile:',
|
||||
unicode: '1f605',
|
||||
),
|
||||
Emoji(
|
||||
char: '😆',
|
||||
shortName: ':laughing:',
|
||||
unicode: '1f606',
|
||||
),
|
||||
Emoji(
|
||||
char: '😇',
|
||||
shortName: ':wink:',
|
||||
unicode: '1f609',
|
||||
),
|
||||
Emoji(
|
||||
char: '😈',
|
||||
shortName: ':smirk:',
|
||||
unicode: '1f60f',
|
||||
),
|
||||
Emoji(
|
||||
char: '😉',
|
||||
shortName: ':wink2:',
|
||||
unicode: '1f609',
|
||||
),
|
||||
Emoji(
|
||||
char: '😊',
|
||||
shortName: ':blush:',
|
||||
unicode: '1f60a',
|
||||
),
|
||||
Emoji(
|
||||
char: '😋',
|
||||
shortName: ':yum:',
|
||||
unicode: '1f60b',
|
||||
),
|
||||
Emoji(
|
||||
char: '😌',
|
||||
shortName: ':relieved:',
|
||||
unicode: '1f60c',
|
||||
),
|
||||
Emoji(
|
||||
char: '😍',
|
||||
shortName: ':heart_eyes:',
|
||||
unicode: '1f60d',
|
||||
),
|
||||
];
|
||||
|
||||
final sampleGroupConversation = [
|
||||
ChatMessage(
|
||||
text: 'Hey there! What\'s up?',
|
||||
createdAt: DateTime.now().subtract(const Duration(seconds: 1)),
|
||||
sender: sahil,
|
||||
),
|
||||
ChatMessage(
|
||||
text: 'Nothing. Just chilling and watching YouTube. What about you?',
|
||||
createdAt: DateTime.now().subtract(const Duration(seconds: 2)),
|
||||
sender: avni,
|
||||
),
|
||||
ChatMessage(
|
||||
text: 'Yeah I know. I\'m in the same position 😂',
|
||||
createdAt: DateTime.now().subtract(const Duration(seconds: 3)),
|
||||
sender: sahil,
|
||||
),
|
||||
ChatMessage(
|
||||
text: 'I\'m just trying to get some sleep',
|
||||
createdAt: DateTime.now().subtract(const Duration(seconds: 4)),
|
||||
sender: gaurav,
|
||||
),
|
||||
ChatMessage(
|
||||
text:
|
||||
'Same here! Been watching YouTube for the past 5 hours despite of having so much to do! 😅',
|
||||
createdAt: DateTime.now().subtract(const Duration(seconds: 5)),
|
||||
sender: trapti,
|
||||
),
|
||||
ChatMessage(
|
||||
text: 'It\'s hard to be productive',
|
||||
createdAt: DateTime.now().subtract(const Duration(seconds: 6)),
|
||||
sender: avni,
|
||||
),
|
||||
];
|
||||
@@ -0,0 +1,49 @@
|
||||
class Emoji {
|
||||
const Emoji({
|
||||
required this.char,
|
||||
required this.shortName,
|
||||
required this.unicode,
|
||||
});
|
||||
|
||||
final String char;
|
||||
final String shortName;
|
||||
final String unicode;
|
||||
}
|
||||
|
||||
class Hashtag {
|
||||
const Hashtag({
|
||||
required this.name,
|
||||
required this.weight,
|
||||
required this.description,
|
||||
required this.image,
|
||||
});
|
||||
|
||||
final String name;
|
||||
final int weight;
|
||||
final String description;
|
||||
final String image;
|
||||
}
|
||||
|
||||
class User {
|
||||
const User({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.avatar,
|
||||
});
|
||||
|
||||
final String id;
|
||||
final String name;
|
||||
final String avatar;
|
||||
}
|
||||
|
||||
class ChatMessage {
|
||||
const ChatMessage({
|
||||
required this.text,
|
||||
required this.createdAt,
|
||||
required this.sender,
|
||||
});
|
||||
|
||||
final String text;
|
||||
final DateTime createdAt;
|
||||
final User sender;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
import 'package:example/src/data.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:example/src/models.dart';
|
||||
|
||||
class EmojiAutocompleteOptions extends StatelessWidget {
|
||||
const EmojiAutocompleteOptions({
|
||||
Key? key,
|
||||
required this.query,
|
||||
required this.onEmojiTap,
|
||||
}) : super(key: key);
|
||||
|
||||
final String query;
|
||||
final ValueSetter<Emoji> onEmojiTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final emojis = kEmojis.where((it) {
|
||||
final normalizedOption = it.shortName.toLowerCase();
|
||||
final normalizedQuery = query.toLowerCase();
|
||||
return normalizedOption.contains(normalizedQuery);
|
||||
});
|
||||
|
||||
if (emojis.isEmpty) return const SizedBox.shrink();
|
||||
|
||||
return Card(
|
||||
margin: const EdgeInsets.all(8),
|
||||
elevation: 2,
|
||||
// color: _streamChatTheme.colorTheme.barsBg,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
color: const Color(0xFFF7F7F8),
|
||||
child: ListTile(
|
||||
dense: true,
|
||||
horizontalTitleGap: 0,
|
||||
title: Text("Emoji's matching '$query'"),
|
||||
),
|
||||
),
|
||||
const Divider(height: 0),
|
||||
LimitedBox(
|
||||
maxHeight: MediaQuery.of(context).size.height * 0.3,
|
||||
child: ListView.separated(
|
||||
padding: EdgeInsets.zero,
|
||||
shrinkWrap: true,
|
||||
itemCount: emojis.length,
|
||||
separatorBuilder: (_, __) => const Divider(height: 0),
|
||||
itemBuilder: (context, i) {
|
||||
final emoji = emojis.elementAt(i);
|
||||
return ListTile(
|
||||
dense: true,
|
||||
leading: Text(
|
||||
emoji.char,
|
||||
style: const TextStyle(fontSize: 24),
|
||||
),
|
||||
title: Text(emoji.shortName),
|
||||
onTap: () => onEmojiTap(emoji),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
import 'package:example/src/data.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:example/src/models.dart';
|
||||
|
||||
class HashtagAutocompleteOptions extends StatelessWidget {
|
||||
const HashtagAutocompleteOptions({
|
||||
Key? key,
|
||||
required this.query,
|
||||
required this.onHashtagTap,
|
||||
}) : super(key: key);
|
||||
|
||||
final String query;
|
||||
final ValueSetter<Hashtag> onHashtagTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final hashtags = kHashtags.where((it) {
|
||||
final normalizedOption = it.name.toLowerCase();
|
||||
final normalizedQuery = query.toLowerCase();
|
||||
return normalizedOption.contains(normalizedQuery);
|
||||
});
|
||||
|
||||
if (hashtags.isEmpty) return const SizedBox.shrink();
|
||||
|
||||
return Card(
|
||||
margin: const EdgeInsets.all(8),
|
||||
elevation: 2,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
color: const Color(0xFFE9EAF4),
|
||||
child: ListTile(
|
||||
dense: true,
|
||||
horizontalTitleGap: 0,
|
||||
title: Text("Hashtags matching '$query'"),
|
||||
),
|
||||
),
|
||||
const Divider(height: 0),
|
||||
LimitedBox(
|
||||
maxHeight: MediaQuery.of(context).size.height * 0.3,
|
||||
child: ListView.separated(
|
||||
padding: EdgeInsets.zero,
|
||||
shrinkWrap: true,
|
||||
itemCount: hashtags.length,
|
||||
separatorBuilder: (_, __) => const Divider(height: 0),
|
||||
itemBuilder: (context, i) {
|
||||
final hashtag = hashtags.elementAt(i);
|
||||
return ListTile(
|
||||
dense: true,
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: const Color(0xFFF7F7F8),
|
||||
backgroundImage: NetworkImage(
|
||||
hashtag.image,
|
||||
scale: 0.5,
|
||||
),
|
||||
),
|
||||
title: Text('#${hashtag.name}'),
|
||||
subtitle: Text(
|
||||
hashtag.description,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
onTap: () => onHashtagTap(hashtag),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
import 'package:example/src/data.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:example/src/models.dart';
|
||||
|
||||
class MentionAutocompleteOptions extends StatelessWidget {
|
||||
const MentionAutocompleteOptions({
|
||||
Key? key,
|
||||
required this.query,
|
||||
required this.onMentionUserTap,
|
||||
}) : super(key: key);
|
||||
|
||||
final String query;
|
||||
final ValueSetter<User> onMentionUserTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final users = kUsers.where((it) {
|
||||
final normalizedId = it.id.toLowerCase();
|
||||
final normalizedName = it.name.toLowerCase();
|
||||
final normalizedQuery = query.toLowerCase();
|
||||
return normalizedId.contains(normalizedQuery) ||
|
||||
normalizedName.contains(normalizedQuery);
|
||||
});
|
||||
|
||||
if (users.isEmpty) return const SizedBox.shrink();
|
||||
|
||||
return Card(
|
||||
margin: const EdgeInsets.all(8),
|
||||
elevation: 2,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
color: const Color(0xFFF7F7F8),
|
||||
child: ListTile(
|
||||
dense: true,
|
||||
horizontalTitleGap: 0,
|
||||
title: Text("Users matching '$query'"),
|
||||
),
|
||||
),
|
||||
LimitedBox(
|
||||
maxHeight: MediaQuery.of(context).size.height * 0.3,
|
||||
child: ListView.separated(
|
||||
padding: EdgeInsets.zero,
|
||||
shrinkWrap: true,
|
||||
itemCount: users.length,
|
||||
separatorBuilder: (_, __) => const Divider(height: 0),
|
||||
itemBuilder: (context, i) {
|
||||
final user = users.elementAt(i);
|
||||
return ListTile(
|
||||
dense: true,
|
||||
leading: CircleAvatar(
|
||||
backgroundImage: NetworkImage(user.avatar),
|
||||
),
|
||||
title: Text(user.name),
|
||||
subtitle: Text('@${user.id}'),
|
||||
onTap: () => onMentionUserTap(user),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export 'emoji_autocomplete_options.dart';
|
||||
export 'hashtag_autocomplete_options.dart';
|
||||
export 'mention_autocomplete_options.dart';
|
||||
Reference in New Issue
Block a user