fix command layout
This commit is contained in:
@@ -14,6 +14,8 @@ PODS:
|
|||||||
- Reachability
|
- Reachability
|
||||||
- path_provider (0.0.1):
|
- path_provider (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- path_provider_macos (0.0.1):
|
||||||
|
- Flutter
|
||||||
- Reachability (3.2)
|
- Reachability (3.2)
|
||||||
- screen (0.0.1):
|
- screen (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
@@ -38,6 +40,7 @@ DEPENDENCIES:
|
|||||||
- image_picker (from `.symlinks/plugins/image_picker/ios`)
|
- image_picker (from `.symlinks/plugins/image_picker/ios`)
|
||||||
- keyboard_visibility (from `.symlinks/plugins/keyboard_visibility/ios`)
|
- keyboard_visibility (from `.symlinks/plugins/keyboard_visibility/ios`)
|
||||||
- path_provider (from `.symlinks/plugins/path_provider/ios`)
|
- path_provider (from `.symlinks/plugins/path_provider/ios`)
|
||||||
|
- path_provider_macos (from `.symlinks/plugins/path_provider_macos/ios`)
|
||||||
- screen (from `.symlinks/plugins/screen/ios`)
|
- screen (from `.symlinks/plugins/screen/ios`)
|
||||||
- sqflite (from `.symlinks/plugins/sqflite/ios`)
|
- sqflite (from `.symlinks/plugins/sqflite/ios`)
|
||||||
- url_launcher (from `.symlinks/plugins/url_launcher/ios`)
|
- url_launcher (from `.symlinks/plugins/url_launcher/ios`)
|
||||||
@@ -64,6 +67,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/keyboard_visibility/ios"
|
:path: ".symlinks/plugins/keyboard_visibility/ios"
|
||||||
path_provider:
|
path_provider:
|
||||||
:path: ".symlinks/plugins/path_provider/ios"
|
:path: ".symlinks/plugins/path_provider/ios"
|
||||||
|
path_provider_macos:
|
||||||
|
:path: ".symlinks/plugins/path_provider_macos/ios"
|
||||||
screen:
|
screen:
|
||||||
:path: ".symlinks/plugins/screen/ios"
|
:path: ".symlinks/plugins/screen/ios"
|
||||||
sqflite:
|
sqflite:
|
||||||
@@ -87,6 +92,7 @@ SPEC CHECKSUMS:
|
|||||||
image_picker: e3eacd46b94694dde7cf2705955cece853aa1a8f
|
image_picker: e3eacd46b94694dde7cf2705955cece853aa1a8f
|
||||||
keyboard_visibility: 96a24de806fe6823c3ad956c01ba2ec6d056616f
|
keyboard_visibility: 96a24de806fe6823c3ad956c01ba2ec6d056616f
|
||||||
path_provider: fb74bd0465e96b594bb3b5088ee4a4e7bb1f2a9d
|
path_provider: fb74bd0465e96b594bb3b5088ee4a4e7bb1f2a9d
|
||||||
|
path_provider_macos: f760a3c5b04357c380e2fddb6f9db6f3015897e0
|
||||||
Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
|
Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
|
||||||
screen: abd91ca7bf3426e1cc3646d27e9b2358d6bf07b0
|
screen: abd91ca7bf3426e1cc3646d27e9b2358d6bf07b0
|
||||||
sqflite: 4001a31ff81d210346b500c55b17f4d6c7589dd0
|
sqflite: 4001a31ff81d210346b500c55b17f4d6c7589dd0
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
final client = Client(
|
final client = Client(
|
||||||
's2dxdhpxd94g',
|
'b67pax5b2wdq',
|
||||||
logLevel: Level.INFO,
|
logLevel: Level.INFO,
|
||||||
);
|
);
|
||||||
|
|
||||||
await client.setUser(
|
await client.setUser(
|
||||||
User(id: 'falling-mountain-7'),
|
User(id: 'falling-mountain-7'),
|
||||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiNDE5MjI5YTMtODRhMC00MDZiLTkzNzEtN2NlOWE0ZTBhNjc2In0.J3SjGH4e4v7b3cg5EgWkljTxXj_HeHpCWn5ujEVv_H8',
|
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiZmFsbGluZy1tb3VudGFpbi03In0.AKgRXHMQQMz6vJAKszXdY8zMFfsAgkoUeZHlI-Szz9E',
|
||||||
);
|
);
|
||||||
|
|
||||||
runApp(MyApp(client));
|
runApp(MyApp(client));
|
||||||
@@ -38,11 +38,11 @@ class ChannelListPage extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: ChannelListView(
|
body: ChannelListView(
|
||||||
// filter: {
|
filter: {
|
||||||
// 'members': {
|
'members': {
|
||||||
// '\$in': [StreamChat.of(context).user.id],
|
'\$in': [StreamChat.of(context).user.id],
|
||||||
// }
|
}
|
||||||
// },
|
},
|
||||||
sort: [SortOption('last_message_at')],
|
sort: [SortOption('last_message_at')],
|
||||||
pagination: PaginationParams(
|
pagination: PaginationParams(
|
||||||
limit: 20,
|
limit: 20,
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
initialData: channel.state.typingEvents,
|
initialData: channel.state.typingEvents,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
final typings = snapshot.data;
|
final typings = snapshot.data;
|
||||||
final opacity = channel.state.unreadCount > .0 ? 1.0 : 0.5;
|
final opacity = channel.state.unreadCount > 0 ? 1.0 : 0.5;
|
||||||
return typings.isNotEmpty
|
return typings.isNotEmpty
|
||||||
? _buildTypings(typings, context, opacity)
|
? _buildTypings(typings, context, opacity)
|
||||||
: _buildLastMessage(context, opacity);
|
: _buildLastMessage(context, opacity);
|
||||||
|
|||||||
+129
-115
@@ -118,10 +118,6 @@ class _MessageInputState extends State<MessageInput> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AnimatedCrossFade _animateSendButton(BuildContext context) {
|
AnimatedCrossFade _animateSendButton(BuildContext context) {
|
||||||
print(
|
|
||||||
'_messageIsPresent || _attachments.isNotEmpty: ${_messageIsPresent || _attachments.isNotEmpty}');
|
|
||||||
print('_attachments.isNotEmpty: ${_attachments.isNotEmpty}');
|
|
||||||
print('_messageIsPresent: ${_messageIsPresent}');
|
|
||||||
return AnimatedCrossFade(
|
return AnimatedCrossFade(
|
||||||
crossFadeState: (_messageIsPresent || _attachments.isNotEmpty)
|
crossFadeState: (_messageIsPresent || _attachments.isNotEmpty)
|
||||||
? CrossFadeState.showFirst
|
? CrossFadeState.showFirst
|
||||||
@@ -214,46 +210,58 @@ class _MessageInputState extends State<MessageInput> {
|
|||||||
|
|
||||||
RenderBox renderBox = context.findRenderObject();
|
RenderBox renderBox = context.findRenderObject();
|
||||||
final size = renderBox.size;
|
final size = renderBox.size;
|
||||||
final offset = renderBox.localToGlobal(Offset.zero);
|
|
||||||
|
|
||||||
return OverlayEntry(builder: (_) {
|
return OverlayEntry(builder: (context) {
|
||||||
return Positioned(
|
return Positioned(
|
||||||
top: offset.dy - size.height,
|
bottom: size.height + MediaQuery.of(context).viewInsets.bottom,
|
||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
child: Material(
|
child: Material(
|
||||||
color: StreamChatTheme.of(context).primaryColor,
|
color: StreamChatTheme.of(context).primaryColor,
|
||||||
child: Flex(
|
child: Container(
|
||||||
mainAxisSize: MainAxisSize.min,
|
constraints: BoxConstraints.loose(Size.fromHeight(400)),
|
||||||
direction: Axis.vertical,
|
decoration: BoxDecoration(
|
||||||
children: <Widget>[
|
boxShadow: [
|
||||||
ListView(
|
BoxShadow(
|
||||||
padding: const EdgeInsets.all(0),
|
spreadRadius: -8,
|
||||||
shrinkWrap: true,
|
blurRadius: 5.0,
|
||||||
children: commands
|
offset: Offset(0, -4),
|
||||||
.map((c) => ListTile(
|
),
|
||||||
title: Text.rich(
|
],
|
||||||
TextSpan(
|
color: StreamChatTheme.of(context).primaryColor,
|
||||||
text: '${c.name}',
|
),
|
||||||
style: TextStyle(fontWeight: FontWeight.bold),
|
child: Flex(
|
||||||
children: [
|
mainAxisSize: MainAxisSize.min,
|
||||||
TextSpan(
|
direction: Axis.vertical,
|
||||||
text: ' ${c.args}',
|
children: <Widget>[
|
||||||
style: TextStyle(
|
ListView(
|
||||||
fontWeight: FontWeight.w300,
|
padding: const EdgeInsets.all(0),
|
||||||
|
shrinkWrap: true,
|
||||||
|
children: commands
|
||||||
|
.map((c) => ListTile(
|
||||||
|
title: Text.rich(
|
||||||
|
TextSpan(
|
||||||
|
text: '${c.name}',
|
||||||
|
style: TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: ' ${c.args}',
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.w300,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
),
|
subtitle: Text(c.description),
|
||||||
subtitle: Text(c.description),
|
onTap: () {
|
||||||
onTap: () {
|
_setCommand(c);
|
||||||
_setCommand(c);
|
},
|
||||||
},
|
))
|
||||||
))
|
.toList(),
|
||||||
.toList(),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -388,71 +396,7 @@ class _MessageInputState extends State<MessageInput> {
|
|||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
showModalBottomSheet(
|
_showAttachmentModal();
|
||||||
clipBehavior: Clip.hardEdge,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.only(
|
|
||||||
topLeft: Radius.circular(32),
|
|
||||||
topRight: Radius.circular(32),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
context: context,
|
|
||||||
builder: (_) {
|
|
||||||
return Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
ListTile(
|
|
||||||
title: Text(
|
|
||||||
'Add a file',
|
|
||||||
style: TextStyle(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
ListTile(
|
|
||||||
leading: Icon(Icons.image),
|
|
||||||
title: Text('Upload a photo'),
|
|
||||||
onTap: () {
|
|
||||||
_pickFile(FileType.IMAGE, false);
|
|
||||||
Navigator.pop(context);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
ListTile(
|
|
||||||
leading: Icon(Icons.video_library),
|
|
||||||
title: Text('Upload a video'),
|
|
||||||
onTap: () {
|
|
||||||
_pickFile(FileType.VIDEO, false);
|
|
||||||
Navigator.pop(context);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
ListTile(
|
|
||||||
leading: Icon(Icons.camera_alt),
|
|
||||||
title: Text('Photo from camera'),
|
|
||||||
onTap: () {
|
|
||||||
ImagePicker.pickImage(source: ImageSource.camera);
|
|
||||||
_pickFile(FileType.IMAGE, true);
|
|
||||||
Navigator.pop(context);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
ListTile(
|
|
||||||
leading: Icon(Icons.videocam),
|
|
||||||
title: Text('Video from camera'),
|
|
||||||
onTap: () {
|
|
||||||
_pickFile(FileType.VIDEO, true);
|
|
||||||
Navigator.pop(context);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
ListTile(
|
|
||||||
leading: Icon(Icons.insert_drive_file),
|
|
||||||
title: Text('Upload a file'),
|
|
||||||
onTap: () {
|
|
||||||
_pickFile(FileType.ANY, false);
|
|
||||||
Navigator.pop(context);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.add_circle_outline,
|
Icons.add_circle_outline,
|
||||||
@@ -461,6 +405,74 @@ class _MessageInputState extends State<MessageInput> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _showAttachmentModal() {
|
||||||
|
showModalBottomSheet(
|
||||||
|
clipBehavior: Clip.hardEdge,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(32),
|
||||||
|
topRight: Radius.circular(32),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
context: context,
|
||||||
|
builder: (_) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
ListTile(
|
||||||
|
title: Text(
|
||||||
|
'Add a file',
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
leading: Icon(Icons.image),
|
||||||
|
title: Text('Upload a photo'),
|
||||||
|
onTap: () {
|
||||||
|
_pickFile(FileType.IMAGE, false);
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
leading: Icon(Icons.video_library),
|
||||||
|
title: Text('Upload a video'),
|
||||||
|
onTap: () {
|
||||||
|
_pickFile(FileType.VIDEO, false);
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
leading: Icon(Icons.camera_alt),
|
||||||
|
title: Text('Photo from camera'),
|
||||||
|
onTap: () {
|
||||||
|
ImagePicker.pickImage(source: ImageSource.camera);
|
||||||
|
_pickFile(FileType.IMAGE, true);
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
leading: Icon(Icons.videocam),
|
||||||
|
title: Text('Video from camera'),
|
||||||
|
onTap: () {
|
||||||
|
_pickFile(FileType.VIDEO, true);
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
leading: Icon(Icons.insert_drive_file),
|
||||||
|
title: Text('Upload a file'),
|
||||||
|
onTap: () {
|
||||||
|
_pickFile(FileType.ANY, false);
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void _pickFile(FileType type, bool camera) async {
|
void _pickFile(FileType type, bool camera) async {
|
||||||
File file;
|
File file;
|
||||||
|
|
||||||
@@ -599,21 +611,23 @@ class _MessageInputState extends State<MessageInput> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
_keyboardListener =
|
_keyboardListener = KeyboardVisibilityNotification().addNewListener(
|
||||||
KeyboardVisibilityNotification().addNewListener(onHide: () {
|
onHide: () {
|
||||||
if (_commandsOverlay != null) {
|
if (_commandsOverlay != null) {
|
||||||
_commandsOverlay.remove();
|
_commandsOverlay.remove();
|
||||||
}
|
|
||||||
}, onShow: () {
|
|
||||||
if (_commandsOverlay != null) {
|
|
||||||
if (_textController.text.startsWith('/')) {
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
||||||
_commandsOverlay = _buildOverlayEntry();
|
|
||||||
Overlay.of(context).insert(_commandsOverlay);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
});
|
onShow: () {
|
||||||
|
if (_commandsOverlay != null) {
|
||||||
|
if (_textController.text.startsWith('/')) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
_commandsOverlay = _buildOverlayEntry();
|
||||||
|
Overlay.of(context).insert(_commandsOverlay);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
if (widget.editMessage != null) {
|
if (widget.editMessage != null) {
|
||||||
_textController = TextEditingController(text: widget.editMessage.text);
|
_textController = TextEditingController(text: widget.editMessage.text);
|
||||||
|
|||||||
+16
-17
@@ -687,26 +687,25 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
}
|
}
|
||||||
|
|
||||||
Row _buildReactionRow() {
|
Row _buildReactionRow() {
|
||||||
final List<Widget> children =
|
|
||||||
widget.message.reactionCounts.keys.map((reactionType) {
|
|
||||||
return Text(
|
|
||||||
reactionToEmoji[reactionType] ?? '?',
|
|
||||||
) as Widget;
|
|
||||||
}).toList();
|
|
||||||
|
|
||||||
children.add(Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 4.0),
|
|
||||||
child: Text(
|
|
||||||
widget.message.reactionCounts.values
|
|
||||||
.fold(0, (t, v) => v + t)
|
|
||||||
.toString(),
|
|
||||||
style: TextStyle(color: Colors.white),
|
|
||||||
),
|
|
||||||
));
|
|
||||||
return Row(
|
return Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: children,
|
children: [
|
||||||
|
...widget.message.reactionCounts.keys.map((reactionType) {
|
||||||
|
return Text(
|
||||||
|
reactionToEmoji[reactionType] ?? '?',
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 4.0),
|
||||||
|
child: Text(
|
||||||
|
widget.message.reactionCounts.values
|
||||||
|
.fold(0, (t, v) => v + t)
|
||||||
|
.toString(),
|
||||||
|
style: TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user