feat: Added ability to add custom attachment types

This commit is contained in:
Deven Joshi
2021-11-04 17:35:21 +05:30
parent e973f98308
commit e72cd81240
@@ -2,7 +2,6 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:image_picker/image_picker.dart';
import 'package:photo_manager/photo_manager.dart';
import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/src/media_list_view.dart';
@@ -15,6 +14,11 @@ typedef FilePickerCallback = void Function(
bool camera,
});
typedef CustomAttachmentIconBuilder = Widget Function(
BuildContext context,
bool active,
);
class StreamAttachmentPicker extends StatefulWidget {
final bool isOpen;
final double pickerSize;
@@ -38,6 +42,8 @@ class StreamAttachmentPicker extends StatefulWidget {
final List<DefaultAttachmentTypes> allowedAttachmentTypes;
final List<CustomAttachmentType> customAttachmentTypes;
const StreamAttachmentPicker({
Key? key,
required this.messageInputController,
@@ -56,6 +62,7 @@ class StreamAttachmentPicker extends StatefulWidget {
DefaultAttachmentTypes.file,
DefaultAttachmentTypes.video,
],
this.customAttachmentTypes = const [],
}) : super(key: key);
@override
@@ -70,9 +77,15 @@ class _StreamAttachmentPickerState extends State<StreamAttachmentPicker> {
var _streamChatTheme = StreamChatTheme.of(context);
var messageInputController = widget.messageInputController;
final _attachmentContainsImage =
messageInputController.attachments.any((it) => it.type == 'image');
final _attachmentContainsFile =
messageInputController.attachments.any((it) => it.type == 'file');
final _attachmentContainsVideo =
messageInputController.attachments.any((it) => it.type == 'video');
final attachmentLimitCrossed =
messageInputController.attachments.length >= widget.attachmentLimit;
@@ -80,12 +93,13 @@ class _StreamAttachmentPickerState extends State<StreamAttachmentPicker> {
final streamChatThemeData = _streamChatTheme;
switch (index) {
case 0:
return messageInputController.attachments.isEmpty
return _filePickerIndex == 0 || _attachmentContainsImage
? streamChatThemeData.colorTheme.accentPrimary
: (!_attachmentContainsFile
: (_attachmentContainsImage
? streamChatThemeData.colorTheme.accentPrimary
: streamChatThemeData.colorTheme.textHighEmphasis
.withOpacity(0.2));
: streamChatThemeData.colorTheme.textHighEmphasis.withOpacity(
messageInputController.attachments.isEmpty ? 0.5 : 0.2,
));
case 1:
return _attachmentContainsFile
? streamChatThemeData.colorTheme.accentPrimary
@@ -95,7 +109,8 @@ class _StreamAttachmentPickerState extends State<StreamAttachmentPicker> {
: streamChatThemeData.colorTheme.textHighEmphasis
.withOpacity(0.2));
case 2:
return attachmentLimitCrossed
return widget.messageInputController.attachments.isNotEmpty &&
(!_attachmentContainsImage || attachmentLimitCrossed)
? streamChatThemeData.colorTheme.textHighEmphasis.withOpacity(0.2)
: _attachmentContainsFile &&
messageInputController.attachments.isNotEmpty
@@ -104,7 +119,8 @@ class _StreamAttachmentPickerState extends State<StreamAttachmentPicker> {
: streamChatThemeData.colorTheme.textHighEmphasis
.withOpacity(0.5);
case 3:
return attachmentLimitCrossed
return widget.messageInputController.attachments.isNotEmpty &&
(!_attachmentContainsVideo || attachmentLimitCrossed)
? streamChatThemeData.colorTheme.textHighEmphasis.withOpacity(0.2)
: _attachmentContainsFile &&
messageInputController.attachments.isNotEmpty
@@ -138,14 +154,15 @@ class _StreamAttachmentPickerState extends State<StreamAttachmentPicker> {
icon: StreamSvgIcon.pictures(
color: _getIconColor(0),
),
onPressed: _attachmentContainsFile &&
messageInputController.attachments.isNotEmpty
? null
: () {
setState(() {
_filePickerIndex = 0;
});
},
onPressed:
messageInputController.attachments.isNotEmpty &&
!_attachmentContainsImage
? null
: () {
setState(() {
_filePickerIndex = 0;
});
},
),
if (widget.allowedAttachmentTypes
.contains(DefaultAttachmentTypes.file))
@@ -154,8 +171,9 @@ class _StreamAttachmentPickerState extends State<StreamAttachmentPicker> {
icon: StreamSvgIcon.files(
color: _getIconColor(1),
),
onPressed: !_attachmentContainsFile &&
messageInputController.attachments.isNotEmpty
onPressed: messageInputController
.attachments.isNotEmpty &&
!_attachmentContainsFile
? null
: () {
widget
@@ -169,9 +187,9 @@ class _StreamAttachmentPickerState extends State<StreamAttachmentPicker> {
color: _getIconColor(2),
),
onPressed: attachmentLimitCrossed ||
(_attachmentContainsFile &&
messageInputController
.attachments.isNotEmpty)
(messageInputController
.attachments.isNotEmpty &&
!_attachmentContainsVideo)
? null
: () {
widget.onFilePicked(
@@ -188,9 +206,9 @@ class _StreamAttachmentPickerState extends State<StreamAttachmentPicker> {
color: _getIconColor(3),
),
onPressed: attachmentLimitCrossed ||
(_attachmentContainsFile &&
messageInputController
.attachments.isNotEmpty)
(messageInputController
.attachments.isNotEmpty &&
!_attachmentContainsVideo)
? null
: () {
widget.onFilePicked(
@@ -199,6 +217,26 @@ class _StreamAttachmentPickerState extends State<StreamAttachmentPicker> {
);
},
),
for (int i = 0;
i < widget.customAttachmentTypes.length;
i++)
IconButton(
onPressed: () {
if (messageInputController.attachments.isNotEmpty) {
if (!messageInputController.attachments.any((e) =>
e.type ==
widget.customAttachmentTypes[i].type)) {
return;
}
}
setState(() {
_filePickerIndex = i + 1;
});
},
icon: widget.customAttachmentTypes[i]
.iconBuilder(context, _filePickerIndex == i + 1),
),
],
),
DecoratedBox(
@@ -252,6 +290,7 @@ class _StreamAttachmentPickerState extends State<StreamAttachmentPicker> {
}
},
allowedAttachmentTypes: widget.allowedAttachmentTypes,
customAttachmentTypes: widget.customAttachmentTypes,
),
),
),
@@ -350,6 +389,7 @@ class _PickerWidget extends StatefulWidget {
required this.onMediaSelected,
required this.streamChatTheme,
required this.allowedAttachmentTypes,
required this.customAttachmentTypes,
}) : super(key: key);
final int filePickerIndex;
@@ -359,6 +399,7 @@ class _PickerWidget extends StatefulWidget {
final void Function(AssetEntity) onMediaSelected;
final StreamChatThemeData streamChatTheme;
final List<DefaultAttachmentTypes> allowedAttachmentTypes;
final List<CustomAttachmentType> customAttachmentTypes;
@override
_PickerWidgetState createState() => _PickerWidgetState();
@@ -376,7 +417,8 @@ class _PickerWidgetState extends State<_PickerWidget> {
@override
Widget build(BuildContext context) {
if (widget.filePickerIndex != 0) {
return const Offstage();
return widget.customAttachmentTypes[widget.filePickerIndex - 1]
.pickerBuilder(context);
}
return FutureBuilder<bool>(
future: requestPermission,
@@ -453,3 +495,15 @@ class _PickerWidgetState extends State<_PickerWidget> {
);
}
}
class CustomAttachmentType {
String type;
CustomAttachmentIconBuilder iconBuilder;
WidgetBuilder pickerBuilder;
CustomAttachmentType({
required this.type,
required this.iconBuilder,
required this.pickerBuilder,
});
}