Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 24 additions & 19 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class _MyHomePageState extends State<MyHomePage> {
body: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
RaisedButton(
ElevatedButton(
child: Text('Get Text'),
onPressed: () {
print(key.currentState!.controller!.markupText);
Expand Down Expand Up @@ -92,26 +92,31 @@ class _MyHomePageState extends State<MyHomePage> {
},
],
matchAll: false,
suggestionBuilder: (data) {
return Container(
padding: EdgeInsets.all(10.0),
child: Row(
children: <Widget>[
CircleAvatar(
backgroundImage: NetworkImage(
data['photo'],
),
),
SizedBox(
width: 20.0,
),
Column(
suggestionBuilder: (data, onTap) {
return Material(
child: InkWell(
onTap: () => onTap.call(data),
child: Container(
padding: EdgeInsets.all(10.0),
child: Row(
children: <Widget>[
Text(data['full_name']),
Text('@${data['display']}'),
CircleAvatar(
backgroundImage: NetworkImage(
data['photo'],
),
),
SizedBox(
width: 20.0,
),
Column(
children: <Widget>[
Text(data['full_name']),
Text('@${data['display']}'),
],
)
],
)
],
),
),
),
);
}),
Expand Down
1 change: 1 addition & 0 deletions lib/flutter_mentions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ part 'src/annotation_editing_controller.dart';
part 'src/mention_view.dart';
part 'src/models.dart';
part 'src/option_list.dart';
part 'src/mentions_to_annotations_converter.dart';
87 changes: 32 additions & 55 deletions lib/src/mention_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ class FlutterMentions extends StatefulWidget {
this.appendSpaceOnAdd = true,
this.hideSuggestionList = false,
this.onSuggestionVisibleChanged,
this.suggestionListWidth,
this.controller,
this.sugggestionContainerBuilder,
}) : super(key: key);

final bool hideSuggestionList;
Expand Down Expand Up @@ -84,6 +87,8 @@ class FlutterMentions extends StatefulWidget {
/// Defaults to `300.0`
final double suggestionListHeight;

final double? suggestionListWidth;

/// A Functioned which is triggered when ever the input changes
/// but with the markup of the selected mentions
///
Expand Down Expand Up @@ -204,7 +209,7 @@ class FlutterMentions extends StatefulWidget {
///
/// This setting is only honored on iOS devices.
///
/// If unset, defaults to the brightness of [ThemeData.primaryColorBrightness].
/// If unset, defaults to the brightness of [ThemeData.brightness].].
final Brightness? keyboardAppearance;

/// {@macro flutter.widgets.editableText.scrollPadding}
Expand Down Expand Up @@ -241,6 +246,9 @@ class FlutterMentions extends StatefulWidget {
/// {@macro flutter.services.autofill.autofillHints}
final Iterable<String>? autofillHints;

final AnnotationEditingController? controller;
final Widget Function(Widget child, BoxConstraints boxConstraints)?
sugggestionContainerBuilder;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo ggg => suggestionContainerBuilder

@override
FlutterMentionsState createState() => FlutterMentionsState();
}
Expand All @@ -251,47 +259,6 @@ class FlutterMentionsState extends State<FlutterMentions> {
LengthMap? _selectedMention;
String _pattern = '';

Map<String, Annotation> mapToAnotation() {
final data = <String, Annotation>{};

// Loop over all the mention items and generate a suggestions matching list
widget.mentions.forEach((element) {
// if matchAll is set to true add a general regex patteren to match with
if (element.matchAll) {
data['${element.trigger}([A-Za-z0-9])*'] = Annotation(
style: element.style,
id: null,
display: null,
trigger: element.trigger,
disableMarkup: element.disableMarkup,
markupBuilder: element.markupBuilder,
);
}

element.data.forEach(
(e) => data["${element.trigger}${e['display']}"] = e['style'] != null
? Annotation(
style: e['style'],
id: e['id'],
display: e['display'],
trigger: element.trigger,
disableMarkup: element.disableMarkup,
markupBuilder: element.markupBuilder,
)
: Annotation(
style: element.style,
id: e['id'],
display: e['display'],
trigger: element.trigger,
disableMarkup: element.disableMarkup,
markupBuilder: element.markupBuilder,
),
);
});

return data;
}

void addMention(Map<String, dynamic> value, [Mention? list]) {
final selectedMention = _selectedMention!;

Expand Down Expand Up @@ -372,9 +339,13 @@ class FlutterMentionsState extends State<FlutterMentions> {

@override
void initState() {
final data = mapToAnotation();

controller = AnnotationEditingController(data);
if (widget.controller == null) {
final data = MentionsToAnnotationsConverter.convert(widget.mentions);
print(data);
controller = AnnotationEditingController(data);
} else {
controller = widget.controller;
}

if (widget.defaultText != null) {
controller!.text = widget.defaultText!;
Expand All @@ -399,8 +370,9 @@ class FlutterMentionsState extends State<FlutterMentions> {
@override
void didUpdateWidget(widget) {
super.didUpdateWidget(widget);

controller!.mapping = mapToAnotation();
controller ??= widget.controller;
controller!.mapping =
MentionsToAnnotationsConverter.convert(widget.mentions);
}

@override
Expand All @@ -412,21 +384,26 @@ class FlutterMentionsState extends State<FlutterMentions> {
: widget.mentions[0];

return Container(
child: PortalEntry(
portalAnchor: widget.suggestionPosition == SuggestionPosition.Bottom
? Alignment.topCenter
: Alignment.bottomCenter,
childAnchor: widget.suggestionPosition == SuggestionPosition.Bottom
? Alignment.bottomCenter
: Alignment.topCenter,
portal: ValueListenableBuilder(
child: PortalTarget(
anchor: Aligned(
follower: widget.suggestionPosition == SuggestionPosition.Bottom
? Alignment.topCenter
: Alignment.bottomCenter,
target: widget.suggestionPosition == SuggestionPosition.Bottom
? Alignment.bottomCenter
: Alignment.topCenter,
),
portalFollower: ValueListenableBuilder(
valueListenable: showSuggestions,
builder: (BuildContext context, bool show, Widget? child) {
return show && !widget.hideSuggestionList
? OptionList(
suggestionListHeight: widget.suggestionListHeight,
suggestionListWidth: widget.suggestionListWidth,
suggestionBuilder: list.suggestionBuilder,
suggestionListDecoration: widget.suggestionListDecoration,
suggestionContainerBuilder:
widget.sugggestionContainerBuilder,
data: list.data.where((element) {
final ele = element['display'].toLowerCase();
final str = _selectedMention!.str
Expand Down
44 changes: 44 additions & 0 deletions lib/src/mentions_to_annotations_converter.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
part of flutter_mentions;

class MentionsToAnnotationsConverter {
static Map<String, Annotation> convert(List<Mention> mentions) {
final data = <String, Annotation>{};

// Loop over all the mention items and generate a suggestions matching list
mentions.forEach((element) {
// if matchAll is set to true add a general regex patteren to match with
if (element.matchAll) {
data['${element.trigger}([A-Za-z0-9])*'] = Annotation(
style: element.style,
id: null,
display: null,
trigger: element.trigger,
disableMarkup: element.disableMarkup,
markupBuilder: element.markupBuilder,
);
}

element.data.forEach(
(e) => data["${element.trigger}${e['display']}"] = e['style'] != null
? Annotation(
style: e['style'],
id: e['id'],
display: e['display'],
trigger: element.trigger,
disableMarkup: element.disableMarkup,
markupBuilder: element.markupBuilder,
)
: Annotation(
style: element.style,
id: e['id'],
display: e['display'],
trigger: element.trigger,
disableMarkup: element.disableMarkup,
markupBuilder: element.markupBuilder,
),
);
});

return data;
}
}
3 changes: 2 additions & 1 deletion lib/src/models.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ class Mention {
final bool disableMarkup;

/// Build Custom suggestion widget using this builder.
final Widget Function(Map<String, dynamic>)? suggestionBuilder;
final Widget Function(Map<String, dynamic> mentionData,
Function(Map<String, dynamic>) onTap)? suggestionBuilder;

/// Allows to set custom markup for the mentioned item.
final String Function(String trigger, String mention, String value)?
Expand Down
69 changes: 39 additions & 30 deletions lib/src/option_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,50 +7,59 @@ class OptionList extends StatelessWidget {
required this.suggestionListHeight,
this.suggestionBuilder,
this.suggestionListDecoration,
this.suggestionListWidth,
this.suggestionContainerBuilder,
});

final Widget Function(Map<String, dynamic>)? suggestionBuilder;
final Widget Function(Map<String, dynamic> mentionData,
Function(Map<String, dynamic>) onTap)? suggestionBuilder;
final Widget Function(Widget child, BoxConstraints boxConstraints)?
suggestionContainerBuilder;

final List<Map<String, dynamic>> data;

final Function(Map<String, dynamic>) onTap;

final double suggestionListHeight;
final double? suggestionListWidth;

final BoxDecoration? suggestionListDecoration;

@override
Widget build(BuildContext context) {
final boxConstraints = BoxConstraints(
maxHeight: suggestionListHeight,
minHeight: 0,
maxWidth: suggestionListWidth ?? double.infinity,
);
final child = ListView.builder(
itemCount: data.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return suggestionBuilder != null
? suggestionBuilder!(data[index], onTap)
: GestureDetector(
onTap: () => onTap(data[index]),
child: Container(
color: Colors.blue,
padding: EdgeInsets.all(20.0),
child: Text(
data[index]['display'],
style: TextStyle(fontSize: 12),
),
),
);
},
);
return data.isNotEmpty
? Container(
decoration:
suggestionListDecoration ?? BoxDecoration(color: Colors.white),
constraints: BoxConstraints(
maxHeight: suggestionListHeight,
minHeight: 0,
),
child: ListView.builder(
itemCount: data.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
onTap(data[index]);
},
child: suggestionBuilder != null
? suggestionBuilder!(data[index])
: Container(
color: Colors.blue,
padding: EdgeInsets.all(20.0),
child: Text(
data[index]['display'],
style: TextStyle(fontSize: 12),
),
),
);
},
),
)
? suggestionContainerBuilder != null
? suggestionContainerBuilder!(child, boxConstraints)
: Container(
decoration: suggestionListDecoration ??
BoxDecoration(color: Colors.white),
constraints: boxConstraints,
child: child,
)
: Container();
}
}
Loading