Merge branch 'soru/event-aggregations' into 'master'

swith to event aggregations and render message edits and reactions

See merge request ChristianPauly/fluffychat-flutter!124
This commit is contained in:
Christian Pauly 2020-08-12 09:30:32 +00:00
commit 098737834e
11 changed files with 514 additions and 152 deletions

View file

@ -1,6 +1,10 @@
# Version 0.17.0 - 2020-08-?? # Version 0.17.0 - 2020-08-??
### Features: ### Features
- Pin and unpin chats - Pin and unpin chats
- Implement event aggregations
- Implement message edits
- Render reactions
- Add / Remove reactions by tapping on existing reactions
### Fixes: ### Fixes:
- Don't re-render the room list nearly as often, increasing performance - Don't re-render the room list nearly as often, increasing performance

View file

@ -12,6 +12,7 @@ import 'package:flutter/material.dart';
import '../adaptive_page_layout.dart'; import '../adaptive_page_layout.dart';
import '../avatar.dart'; import '../avatar.dart';
import '../matrix.dart'; import '../matrix.dart';
import '../message_reactions.dart';
import 'state_message.dart'; import 'state_message.dart';
class Message extends StatelessWidget { class Message extends StatelessWidget {
@ -64,11 +65,13 @@ class Message extends StatelessWidget {
var rowMainAxisAlignment = var rowMainAxisAlignment =
ownMessage ? MainAxisAlignment.end : MainAxisAlignment.start; ownMessage ? MainAxisAlignment.end : MainAxisAlignment.start;
final displayEvent = event.getDisplayEvent(timeline);
if (event.showThumbnail) { if (event.showThumbnail) {
color = Theme.of(context).scaffoldBackgroundColor.withOpacity(0.66); color = Theme.of(context).scaffoldBackgroundColor.withOpacity(0.66);
textColor = Theme.of(context).textTheme.bodyText2.color; textColor = Theme.of(context).textTheme.bodyText2.color;
} else if (ownMessage) { } else if (ownMessage) {
color = event.status == -1 color = displayEvent.status == -1
? Colors.redAccent ? Colors.redAccent
: Theme.of(context).primaryColor; : Theme.of(context).primaryColor;
} }
@ -91,15 +94,14 @@ class Message extends StatelessWidget {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
if (event.isReply) if (event.relationshipType == RelationshipTypes.Reply)
FutureBuilder<Event>( FutureBuilder<Event>(
future: event.getReplyEvent(timeline), future: event.getReplyEvent(timeline),
builder: (BuildContext context, snapshot) { builder: (BuildContext context, snapshot) {
final replyEvent = snapshot.hasData final replyEvent = snapshot.hasData
? snapshot.data ? snapshot.data
: Event( : Event(
eventId: event.content['m.relates_to'] eventId: event.relationshipEventId,
['m.in_reply_to']['event_id'],
content: {'msgtype': 'm.text', 'body': '...'}, content: {'msgtype': 'm.text', 'body': '...'},
senderId: event.senderId, senderId: event.senderId,
type: 'm.room.message', type: 'm.room.message',
@ -110,18 +112,18 @@ class Message extends StatelessWidget {
); );
return Container( return Container(
margin: EdgeInsets.symmetric(vertical: 4.0), margin: EdgeInsets.symmetric(vertical: 4.0),
child: child: ReplyContent(replyEvent,
ReplyContent(replyEvent, lightText: ownMessage), lightText: ownMessage, timeline: timeline),
); );
}, },
), ),
MessageContent( MessageContent(
event, displayEvent,
textColor: textColor, textColor: textColor,
), ),
if (event.type == EventTypes.Encrypted && if (displayEvent.type == EventTypes.Encrypted &&
event.messageType == MessageTypes.BadEncrypted && displayEvent.messageType == MessageTypes.BadEncrypted &&
event.content['can_request_session'] == true) displayEvent.content['can_request_session'] == true)
RaisedButton( RaisedButton(
color: color.withAlpha(100), color: color.withAlpha(100),
child: Text( child: Text(
@ -129,15 +131,18 @@ class Message extends StatelessWidget {
style: TextStyle(color: textColor), style: TextStyle(color: textColor),
), ),
onPressed: () => SimpleDialogs(context) onPressed: () => SimpleDialogs(context)
.tryRequestWithLoadingDialog(event.requestKey()), .tryRequestWithLoadingDialog(
displayEvent.requestKey()),
), ),
SizedBox(height: 4), SizedBox(height: 4),
Opacity( Opacity(
opacity: 0, opacity: 0,
child: _MetaRow( child: _MetaRow(
event, event, // meta information should be from the unedited event
ownMessage, ownMessage,
textColor, textColor,
timeline,
displayEvent,
), ),
), ),
], ],
@ -150,6 +155,8 @@ class Message extends StatelessWidget {
event, event,
ownMessage, ownMessage,
textColor, textColor,
timeline,
displayEvent,
), ),
), ),
], ],
@ -170,6 +177,32 @@ class Message extends StatelessWidget {
} else { } else {
rowChildren.insert(0, avatarOrSizedBox); rowChildren.insert(0, avatarOrSizedBox);
} }
final row = Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: rowMainAxisAlignment,
children: rowChildren,
);
Widget container;
if (event.hasAggregatedEvents(timeline, RelationshipTypes.Reaction)) {
container = Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment:
ownMessage ? CrossAxisAlignment.end : CrossAxisAlignment.start,
children: <Widget>[
row,
Padding(
padding: EdgeInsets.only(
top: 4.0,
left: (ownMessage ? 0 : Avatar.defaultSize) + 12.0,
right: (ownMessage ? Avatar.defaultSize : 0) + 12.0,
),
child: MessageReactions(event, timeline),
),
],
);
} else {
container = row;
}
return InkWell( return InkWell(
onHover: (b) => useMouse = true, onHover: (b) => useMouse = true,
@ -185,11 +218,7 @@ class Message extends StatelessWidget {
child: Padding( child: Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(
left: 8.0, right: 8.0, bottom: sameSender ? 4.0 : 8.0), left: 8.0, right: 8.0, bottom: sameSender ? 4.0 : 8.0),
child: Row( child: container,
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: rowMainAxisAlignment,
children: rowChildren,
),
), ),
), ),
); );
@ -200,8 +229,12 @@ class _MetaRow extends StatelessWidget {
final Event event; final Event event;
final bool ownMessage; final bool ownMessage;
final Color color; final Color color;
final Timeline timeline;
final Event displayEvent;
const _MetaRow(this.event, this.ownMessage, this.color, {Key key}) const _MetaRow(
this.event, this.ownMessage, this.color, this.timeline, this.displayEvent,
{Key key})
: super(key: key); : super(key: key);
@override @override
@ -229,10 +262,16 @@ class _MetaRow extends StatelessWidget {
fontSize: 11, fontSize: 11,
), ),
), ),
if (event.hasAggregatedEvents(timeline, RelationshipTypes.Edit))
Icon(
Icons.edit,
size: 12,
color: color,
),
if (ownMessage) SizedBox(width: 2), if (ownMessage) SizedBox(width: 2),
if (ownMessage) if (ownMessage)
Icon( Icon(
event.statusIcon, displayEvent.statusIcon,
size: 12, size: 12,
color: color, color: color,
), ),

View file

@ -194,7 +194,6 @@ class MatrixState extends State<Matrix> {
verificationMethods.add(KeyVerificationMethod.emoji); verificationMethods.add(KeyVerificationMethod.emoji);
} }
client = Client(widget.clientName, client = Client(widget.clientName,
debug: false,
enableE2eeRecovery: true, enableE2eeRecovery: true,
verificationMethods: verificationMethods, verificationMethods: verificationMethods,
importantStateEvents: <String>{ importantStateEvents: <String>{

View file

@ -40,7 +40,6 @@ class MessageContent extends StatelessWidget {
case MessageTypes.Text: case MessageTypes.Text:
case MessageTypes.Notice: case MessageTypes.Notice:
case MessageTypes.Emote: case MessageTypes.Emote:
case MessageTypes.Reply:
if (Matrix.of(context).renderHtml && if (Matrix.of(context).renderHtml &&
!event.redacted && !event.redacted &&
event.content['format'] == 'org.matrix.custom.html' && event.content['format'] == 'org.matrix.custom.html' &&

View file

@ -0,0 +1,140 @@
import 'package:famedlysdk/famedlysdk.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_advanced_networkimage/provider.dart';
import 'matrix.dart';
class MessageReactions extends StatelessWidget {
final Event event;
final Timeline timeline;
const MessageReactions(this.event, this.timeline);
@override
Widget build(BuildContext context) {
final allReactionEvents =
event.aggregatedEvents(timeline, RelationshipTypes.Reaction);
final reactionMap = <String, _ReactionEntry>{};
for (final e in allReactionEvents) {
if (e.content['m.relates_to'].containsKey('key')) {
final key = e.content['m.relates_to']['key'];
if (!reactionMap.containsKey(key)) {
reactionMap[key] = _ReactionEntry(
key: key,
count: 0,
reacted: false,
);
}
reactionMap[key].count++;
reactionMap[key].reacted |= e.senderId == e.room.client.userID;
}
}
final reactionList = reactionMap.values.toList();
reactionList.sort((a, b) => b.count - a.count > 0 ? 1 : -1);
return Wrap(
spacing: 4.0,
runSpacing: 4.0,
children: reactionList
.map((r) => _Reaction(
reactionKey: r.key,
count: r.count,
reacted: r.reacted,
onTap: () {
if (r.reacted) {
final evt = allReactionEvents.firstWhere(
(e) =>
e.senderId == e.room.client.userID &&
e.content['m.relates_to']['key'] == r.key,
orElse: () => null);
if (evt != null) {
evt.redact();
}
} else {
event.room.sendReaction(event.eventId, r.key);
}
},
))
.toList(),
);
}
}
class _Reaction extends StatelessWidget {
final String reactionKey;
final int count;
final bool reacted;
final void Function() onTap;
const _Reaction({this.reactionKey, this.count, this.reacted, this.onTap});
@override
Widget build(BuildContext context) {
final borderColor = reacted ? Colors.red : Theme.of(context).primaryColor;
final textColor = Theme.of(context).brightness == Brightness.dark
? Colors.white
: Colors.black;
final color = Theme.of(context).secondaryHeaderColor;
final fontSize = DefaultTextStyle.of(context).style.fontSize;
final padding = fontSize / 5;
Widget content;
if (reactionKey.startsWith('mxc://')) {
final src = Uri.parse(reactionKey)?.getThumbnail(
Matrix.of(context).client,
width: 9999,
height: fontSize * MediaQuery.of(context).devicePixelRatio,
method: ThumbnailMethod.scale,
);
content = Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Image(
image: AdvancedNetworkImage(
src,
useDiskCache: !kIsWeb,
),
height: fontSize,
),
Text(count.toString(),
style: TextStyle(
color: textColor,
fontSize: DefaultTextStyle.of(context).style.fontSize,
)),
],
);
} else {
var renderKey = reactionKey;
if (renderKey.length > 10) {
renderKey = renderKey.substring(0, 7) + '...';
}
content = Text('$renderKey $count',
style: TextStyle(
color: textColor,
fontSize: DefaultTextStyle.of(context).style.fontSize,
));
}
return InkWell(
child: Container(
decoration: BoxDecoration(
color: color,
border: Border.all(
width: fontSize / 20,
color: borderColor,
),
borderRadius: BorderRadius.all(Radius.circular(padding * 2)),
),
padding: EdgeInsets.all(padding),
child: content,
),
onTap: () => onTap != null ? onTap() : null,
);
}
}
class _ReactionEntry {
String key;
int count;
bool reacted;
_ReactionEntry({this.key, this.count, this.reacted});
}

View file

@ -8,23 +8,29 @@ import 'matrix.dart';
class ReplyContent extends StatelessWidget { class ReplyContent extends StatelessWidget {
final Event replyEvent; final Event replyEvent;
final bool lightText; final bool lightText;
final Timeline timeline;
const ReplyContent(this.replyEvent, {this.lightText = false, Key key}) const ReplyContent(this.replyEvent,
{this.lightText = false, Key key, this.timeline})
: super(key: key); : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Widget replyBody; Widget replyBody;
if (replyEvent != null && final displayEvent = replyEvent != null && timeline != null
? replyEvent.getDisplayEvent(timeline)
: replyEvent;
if (displayEvent != null &&
Matrix.of(context).renderHtml && Matrix.of(context).renderHtml &&
[EventTypes.Message, EventTypes.Encrypted].contains(replyEvent.type) && [EventTypes.Message, EventTypes.Encrypted]
.contains(displayEvent.type) &&
[MessageTypes.Text, MessageTypes.Notice, MessageTypes.Emote] [MessageTypes.Text, MessageTypes.Notice, MessageTypes.Emote]
.contains(replyEvent.messageType) && .contains(displayEvent.messageType) &&
!replyEvent.redacted && !displayEvent.redacted &&
replyEvent.content['format'] == 'org.matrix.custom.html' && displayEvent.content['format'] == 'org.matrix.custom.html' &&
replyEvent.content['formatted_body'] is String) { displayEvent.content['formatted_body'] is String) {
String html = replyEvent.content['formatted_body']; String html = displayEvent.content['formatted_body'];
if (replyEvent.messageType == MessageTypes.Emote) { if (displayEvent.messageType == MessageTypes.Emote) {
html = '* $html'; html = '* $html';
} }
replyBody = HtmlMessage( replyBody = HtmlMessage(
@ -36,11 +42,11 @@ class ReplyContent extends StatelessWidget {
fontSize: DefaultTextStyle.of(context).style.fontSize, fontSize: DefaultTextStyle.of(context).style.fontSize,
), ),
maxLines: 1, maxLines: 1,
room: replyEvent.room, room: displayEvent.room,
); );
} else { } else {
replyBody = Text( replyBody = Text(
replyEvent?.getLocalizedBody( displayEvent?.getLocalizedBody(
L10n.of(context), L10n.of(context),
withSenderNamePrefix: false, withSenderNamePrefix: false,
hideReply: true, hideReply: true,
@ -71,7 +77,7 @@ class ReplyContent extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[
Text( Text(
(replyEvent?.sender?.calcDisplayname() ?? '') + ':', (displayEvent?.sender?.calcDisplayname() ?? '') + ':',
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: TextStyle( style: TextStyle(

View file

@ -8,6 +8,18 @@ import 'package:moor/moor.dart';
import 'package:moor/isolate.dart'; import 'package:moor/isolate.dart';
import 'cipher_db.dart' as cipher; import 'cipher_db.dart' as cipher;
class DatabaseNoTransactions extends Database {
DatabaseNoTransactions.connect(DatabaseConnection connection)
: super.connect(connection);
// moor transactions are sometimes rather weird and freeze. Until there is a
// proper fix in moor we override that there aren't actually using transactions
@override
Future<T> transaction<T>(Future<T> Function() action) async {
return action();
}
}
bool _inited = false; bool _inited = false;
// see https://moor.simonbinder.eu/docs/advanced-features/isolates/ // see https://moor.simonbinder.eu/docs/advanced-features/isolates/
@ -57,7 +69,7 @@ Future<Database> constructDb(
receivePort.sendPort, targetPath, password, logStatements), receivePort.sendPort, targetPath, password, logStatements),
); );
final isolate = (await receivePort.first as MoorIsolate); final isolate = (await receivePort.first as MoorIsolate);
return Database.connect(await isolate.connect()); return DatabaseNoTransactions.connect(await isolate.connect());
} }
Future<String> getLocalstorage(String key) async { Future<String> getLocalstorage(String key) async {

View file

@ -161,7 +161,7 @@ abstract class FirebaseController {
} else { } else {
final platform = kIsWeb ? 'Web' : Platform.operatingSystem; final platform = kIsWeb ? 'Web' : Platform.operatingSystem;
final clientName = 'FluffyChat $platform'; final clientName = 'FluffyChat $platform';
client = Client(clientName, debug: false); client = Client(clientName);
client.database = await getDatabase(client); client.database = await getDatabase(client);
client.connect(); client.connect();
await client.onLoginStateChanged.stream await client.onLoginStateChanged.stream

View file

@ -76,6 +76,8 @@ class _ChatState extends State<_Chat> {
Event replyEvent; Event replyEvent;
Event editEvent;
bool showScrollDownButton = false; bool showScrollDownButton = false;
bool get selectMode => selectedEvents.isNotEmpty; bool get selectMode => selectedEvents.isNotEmpty;
@ -174,13 +176,15 @@ class _ChatState extends State<_Chat> {
void send() { void send() {
if (sendController.text.isEmpty) return; if (sendController.text.isEmpty) return;
room.sendTextEvent(sendController.text, inReplyTo: replyEvent); room.sendTextEvent(sendController.text,
inReplyTo: replyEvent, editEventId: editEvent?.eventId);
sendController.text = ''; sendController.text = '';
if (replyEvent != null) {
setState(() => replyEvent = null);
}
setState(() => inputText = ''); setState(() {
inputText = '';
replyEvent = null;
editEvent = null;
});
} }
void sendFileAction(BuildContext context) async { void sendFileAction(BuildContext context) async {
@ -289,8 +293,17 @@ class _ChatState extends State<_Chat> {
Navigator.of(context).popUntil((r) => r.isFirst); Navigator.of(context).popUntil((r) => r.isFirst);
} }
void sendAgainAction() { void sendAgainAction(Timeline timeline) {
selectedEvents.first.sendAgain(); final event = selectedEvents.first;
if (event.status == -1) {
event.sendAgain();
}
final allEditEvents = event
.aggregatedEvents(timeline, RelationshipTypes.Edit)
.where((e) => e.status == -1);
for (final e in allEditEvents) {
e.sendAgain();
}
setState(() => selectedEvents.clear()); setState(() => selectedEvents.clear());
} }
@ -411,6 +424,23 @@ class _ChatState extends State<_Chat> {
.numberSelected(selectedEvents.length.toString())), .numberSelected(selectedEvents.length.toString())),
actions: selectMode actions: selectMode
? <Widget>[ ? <Widget>[
if (selectedEvents.length == 1 &&
selectedEvents.first.status > 0 &&
selectedEvents.first.senderId == client.userID)
IconButton(
icon: Icon(Icons.edit),
onPressed: () {
setState(() {
editEvent = selectedEvents.first;
sendController.text = editEvent
.getDisplayEvent(timeline)
.getLocalizedBody(L10n.of(context),
withSenderNamePrefix: false, hideReply: true);
selectedEvents.clear();
});
inputFocus.requestFocus();
},
),
IconButton( IconButton(
icon: Icon(Icons.content_copy), icon: Icon(Icons.content_copy),
onPressed: () => copyEventsAction(context), onPressed: () => copyEventsAction(context),
@ -467,7 +497,16 @@ class _ChatState extends State<_Chat> {
room.sendReadReceipt(timeline.events.first.eventId); room.sendReadReceipt(timeline.events.first.eventId);
} }
if (timeline.events.isEmpty) return Container(); final filteredEvents = timeline.events
.where((e) =>
![
RelationshipTypes.Edit,
RelationshipTypes.Reaction
].contains(e.relationshipType) &&
e.type != 'm.reaction')
.toList();
if (filteredEvents.isEmpty) return Container();
return ListView.builder( return ListView.builder(
padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(
@ -479,10 +518,10 @@ class _ChatState extends State<_Chat> {
2), 2),
), ),
reverse: true, reverse: true,
itemCount: timeline.events.length + 2, itemCount: filteredEvents.length + 2,
controller: _scrollController, controller: _scrollController,
itemBuilder: (BuildContext context, int i) { itemBuilder: (BuildContext context, int i) {
return i == timeline.events.length + 1 return i == filteredEvents.length + 1
? _loadingHistory ? _loadingHistory
? Container( ? Container(
height: 50, height: 50,
@ -512,7 +551,7 @@ class _ChatState extends State<_Chat> {
? Duration(milliseconds: 0) ? Duration(milliseconds: 0)
: Duration(milliseconds: 500), : Duration(milliseconds: 500),
alignment: alignment:
timeline.events.first.senderId == filteredEvents.first.senderId ==
client.userID client.userID
? Alignment.topRight ? Alignment.topRight
: Alignment.topLeft, : Alignment.topLeft,
@ -530,7 +569,7 @@ class _ChatState extends State<_Chat> {
bottom: 8, bottom: 8,
), ),
) )
: Message(timeline.events[i - 1], : Message(filteredEvents[i - 1],
onAvatarTab: (Event event) { onAvatarTab: (Event event) {
sendController.text += sendController.text +=
' ${event.senderId}'; ' ${event.senderId}';
@ -553,10 +592,10 @@ class _ChatState extends State<_Chat> {
}, },
longPressSelect: selectedEvents.isEmpty, longPressSelect: selectedEvents.isEmpty,
selected: selectedEvents selected: selectedEvents
.contains(timeline.events[i - 1]), .contains(filteredEvents[i - 1]),
timeline: timeline, timeline: timeline,
nextEvent: i >= 2 nextEvent: i >= 2
? timeline.events[i - 2] ? filteredEvents[i - 2]
: null); : null);
}); });
}, },
@ -565,17 +604,23 @@ class _ChatState extends State<_Chat> {
ConnectionStatusHeader(), ConnectionStatusHeader(),
AnimatedContainer( AnimatedContainer(
duration: Duration(milliseconds: 300), duration: Duration(milliseconds: 300),
height: replyEvent != null ? 56 : 0, height: editEvent != null || replyEvent != null ? 56 : 0,
child: Material( child: Material(
color: Theme.of(context).secondaryHeaderColor, color: Theme.of(context).secondaryHeaderColor,
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
IconButton( IconButton(
icon: Icon(Icons.close), icon: Icon(Icons.close),
onPressed: () => setState(() => replyEvent = null), onPressed: () => setState(() {
replyEvent = null;
editEvent = null;
}),
), ),
Expanded( Expanded(
child: ReplyContent(replyEvent), child: replyEvent != null
? ReplyContent(replyEvent, timeline: timeline)
: _EditContent(
editEvent?.getDisplayEvent(timeline)),
), ),
], ],
), ),
@ -611,7 +656,10 @@ class _ChatState extends State<_Chat> {
), ),
), ),
selectedEvents.length == 1 selectedEvents.length == 1
? selectedEvents.first.status > 0 ? selectedEvents.first
.getDisplayEvent(timeline)
.status >
0
? Container( ? Container(
height: 56, height: 56,
child: FlatButton( child: FlatButton(
@ -629,7 +677,7 @@ class _ChatState extends State<_Chat> {
height: 56, height: 56,
child: FlatButton( child: FlatButton(
onPressed: () => onPressed: () =>
sendAgainAction(), sendAgainAction(timeline),
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
Text(L10n.of(context) Text(L10n.of(context)
@ -804,3 +852,38 @@ class _ChatState extends State<_Chat> {
); );
} }
} }
class _EditContent extends StatelessWidget {
final Event event;
_EditContent(this.event);
@override
Widget build(BuildContext context) {
if (event == null) {
return Container();
}
return Row(
children: <Widget>[
Icon(
Icons.edit,
color: Theme.of(context).primaryColor,
),
Container(width: 15.0),
Text(
event?.getLocalizedBody(
L10n.of(context),
withSenderNamePrefix: false,
hideReply: true,
) ??
'',
overflow: TextOverflow.ellipsis,
maxLines: 1,
style: TextStyle(
color: Theme.of(context).textTheme.bodyText2.color,
),
),
],
);
}
}

View file

@ -14,7 +14,14 @@ packages:
name: analyzer name: analyzer
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.39.15" version: "0.39.16"
ansicolor:
dependency: transitive
description:
name: ansicolor
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
archive: archive:
dependency: transitive dependency: transitive
description: description:
@ -35,14 +42,14 @@ packages:
name: asn1lib name: asn1lib
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.6.4" version: "0.6.5"
async: async:
dependency: transitive dependency: transitive
description: description:
name: async name: async
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.4.1" version: "2.4.2"
base58check: base58check:
dependency: transitive dependency: transitive
description: description:
@ -63,7 +70,7 @@ packages:
name: bot_toast name: bot_toast
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.0.0" version: "3.0.1"
bubble: bubble:
dependency: "direct main" dependency: "direct main"
description: description:
@ -78,6 +85,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.0" version: "1.0.0"
characters:
dependency: transitive
description:
name: characters
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
charcode: charcode:
dependency: transitive dependency: transitive
description: description:
@ -105,7 +119,7 @@ packages:
name: collection name: collection
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.14.12" version: "1.14.13"
convert: convert:
dependency: transitive dependency: transitive
description: description:
@ -119,21 +133,21 @@ packages:
name: coverage name: coverage
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.13.6" version: "0.14.0"
crypto: crypto:
dependency: transitive dependency: transitive
description: description:
name: crypto name: crypto
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.4" version: "2.1.5"
csslib: csslib:
dependency: transitive dependency: transitive
description: description:
name: csslib name: csslib
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.16.1" version: "0.16.2"
cupertino_icons: cupertino_icons:
dependency: "direct main" dependency: "direct main"
description: description:
@ -147,7 +161,7 @@ packages:
name: dart_style name: dart_style
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.3.3" version: "1.3.6"
encrypt: encrypt:
dependency: transitive dependency: transitive
description: description:
@ -155,12 +169,19 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "4.0.2" version: "4.0.2"
fake_async:
dependency: transitive
description:
name: fake_async
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
famedlysdk: famedlysdk:
dependency: "direct main" dependency: "direct main"
description: description:
path: "." path: "."
ref: "3fae58439bdc2100d26fbfb92a62c7fbb7b48903" ref: "574fe27101bb03c8c18c776e98f7f44668e6d159"
resolved-ref: "3fae58439bdc2100d26fbfb92a62c7fbb7b48903" resolved-ref: "574fe27101bb03c8c18c776e98f7f44668e6d159"
url: "https://gitlab.com/famedly/famedlysdk.git" url: "https://gitlab.com/famedly/famedlysdk.git"
source: git source: git
version: "0.0.1" version: "0.0.1"
@ -171,27 +192,34 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.3" version: "0.1.3"
file:
dependency: transitive
description:
name: file
url: "https://pub.dartlang.org"
source: hosted
version: "5.2.1"
file_picker: file_picker:
dependency: transitive dependency: transitive
description: description:
name: file_picker name: file_picker
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.12.0" version: "1.13.2"
file_picker_platform_interface: file_picker_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: file_picker_platform_interface name: file_picker_platform_interface
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.0" version: "1.3.1"
firebase_messaging: firebase_messaging:
dependency: "direct main" dependency: "direct main"
description: description:
name: firebase_messaging name: firebase_messaging
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "6.0.13" version: "6.0.16"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -200,31 +228,33 @@ packages:
flutter_advanced_networkimage: flutter_advanced_networkimage:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_advanced_networkimage path: "."
url: "https://pub.dartlang.org" ref: master
source: hosted resolved-ref: f0f599fb89c494d9158fb6f13d4870582f8ecfcb
version: "0.6.4" url: "https://github.com/mchome/flutter_advanced_networkimage"
source: git
version: "0.8.0"
flutter_keyboard_visibility: flutter_keyboard_visibility:
dependency: transitive dependency: transitive
description: description:
name: flutter_keyboard_visibility name: flutter_keyboard_visibility
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.7.0" version: "3.2.1"
flutter_launcher_icons: flutter_launcher_icons:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: flutter_launcher_icons name: flutter_launcher_icons
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.7.4" version: "0.7.5"
flutter_local_notifications: flutter_local_notifications:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_local_notifications name: flutter_local_notifications
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.4.3" version: "1.4.4+2"
flutter_local_notifications_platform_interface: flutter_local_notifications_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -240,9 +270,11 @@ packages:
flutter_matrix_html: flutter_matrix_html:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_matrix_html path: "."
url: "https://pub.dartlang.org" ref: "530df434b50002e04cbad63f53d6f0f5d5adbab5"
source: hosted resolved-ref: "530df434b50002e04cbad63f53d6f0f5d5adbab5"
url: "https://github.com/Sorunome/flutter_matrix_html"
source: git
version: "0.1.2" version: "0.1.2"
flutter_olm: flutter_olm:
dependency: "direct main" dependency: "direct main"
@ -264,14 +296,14 @@ packages:
name: flutter_secure_storage name: flutter_secure_storage
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.3.1+1" version: "3.3.3"
flutter_slidable: flutter_slidable:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_slidable name: flutter_slidable
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.5.4" version: "0.5.5"
flutter_sound: flutter_sound:
dependency: "direct main" dependency: "direct main"
description: description:
@ -285,7 +317,7 @@ packages:
name: flutter_svg name: flutter_svg
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.17.4" version: "0.18.0"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
@ -297,7 +329,7 @@ packages:
name: flutter_typeahead name: flutter_typeahead
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.8.1" version: "1.8.7"
flutter_web_plugins: flutter_web_plugins:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -330,7 +362,7 @@ packages:
name: http name: http
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.12.1" version: "0.12.2"
http_multi_server: http_multi_server:
dependency: transitive dependency: transitive
description: description:
@ -344,21 +376,21 @@ packages:
name: http_parser name: http_parser
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.1.3" version: "3.1.4"
image: image:
dependency: transitive dependency: transitive
description: description:
name: image name: image
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.12" version: "2.1.14"
image_picker: image_picker:
dependency: transitive dependency: transitive
description: description:
name: image_picker name: image_picker
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.6.7+2" version: "0.6.7+4"
image_picker_platform_interface: image_picker_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -379,35 +411,35 @@ packages:
name: intl_translation name: intl_translation
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.17.9" version: "0.17.10"
io: io:
dependency: transitive dependency: transitive
description: description:
name: io name: io
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.3.3" version: "0.3.4"
js: js:
dependency: transitive dependency: transitive
description: description:
name: js name: js
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.6.1+1" version: "0.6.2"
link_text: link_text:
dependency: "direct main" dependency: "direct main"
description: description:
name: link_text name: link_text
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.1" version: "0.1.2"
localstorage: localstorage:
dependency: "direct main" dependency: "direct main"
description: description:
name: localstorage name: localstorage
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.0.1+4" version: "3.0.2+5"
logging: logging:
dependency: transitive dependency: transitive
description: description:
@ -421,14 +453,14 @@ packages:
name: markdown name: markdown
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.3" version: "2.1.7"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
name: matcher name: matcher
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.12.6" version: "0.12.8"
matrix_file_e2ee: matrix_file_e2ee:
dependency: transitive dependency: transitive
description: description:
@ -463,14 +495,14 @@ packages:
name: mime_type name: mime_type
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.3.0" version: "0.3.2"
moor: moor:
dependency: "direct main" dependency: "direct main"
description: description:
name: moor name: moor
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.0.2" version: "3.3.0"
moor_ffi: moor_ffi:
dependency: "direct main" dependency: "direct main"
description: description:
@ -478,34 +510,27 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.5.0" version: "0.5.0"
multi_server_socket:
dependency: transitive
description:
name: multi_server_socket
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
node_interop: node_interop:
dependency: transitive dependency: transitive
description: description:
name: node_interop name: node_interop
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.3" version: "1.1.1"
node_io: node_io:
dependency: transitive dependency: transitive
description: description:
name: node_io name: node_io
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.1+2" version: "1.1.1"
node_preamble: node_preamble:
dependency: transitive dependency: transitive
description: description:
name: node_preamble name: node_preamble
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.4.8" version: "1.4.12"
olm: olm:
dependency: transitive dependency: transitive
description: description:
@ -527,13 +552,6 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.9.3" version: "1.9.3"
package_resolver:
dependency: transitive
description:
name: package_resolver
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.10"
password_hash: password_hash:
dependency: transitive dependency: transitive
description: description:
@ -547,7 +565,7 @@ packages:
name: path name: path
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.6.4" version: "1.7.0"
path_drawing: path_drawing:
dependency: transitive dependency: transitive
description: description:
@ -568,7 +586,28 @@ packages:
name: path_provider name: path_provider
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.5.1" version: "1.6.11"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.1+2"
path_provider_macos:
dependency: transitive
description:
name: path_provider_macos
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.4+3"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
pedantic: pedantic:
dependency: "direct dev" dependency: "direct dev"
description: description:
@ -582,7 +621,7 @@ packages:
name: petitparser name: petitparser
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.4.0" version: "3.0.4"
photo_view: photo_view:
dependency: "direct main" dependency: "direct main"
description: description:
@ -597,6 +636,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.2.1" version: "2.2.1"
platform_detect:
dependency: transitive
description:
name: platform_detect
url: "https://pub.dartlang.org"
source: hosted
version: "1.4.0"
plugin_platform_interface: plugin_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -618,55 +664,55 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.4.0" version: "1.4.0"
process:
dependency: transitive
description:
name: process
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.13"
pub_semver: pub_semver:
dependency: transitive dependency: transitive
description: description:
name: pub_semver name: pub_semver
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.4.2" version: "1.4.4"
quiver:
dependency: transitive
description:
name: quiver
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.3"
random_string: random_string:
dependency: "direct main" dependency: "direct main"
description: description:
name: random_string name: random_string
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.1" version: "2.1.0"
receive_sharing_intent: receive_sharing_intent:
dependency: "direct main" dependency: "direct main"
description: description:
name: receive_sharing_intent name: receive_sharing_intent
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.3.3" version: "1.4.0+2"
share: share:
dependency: "direct main" dependency: "direct main"
description: description:
name: share name: share
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.6.3+5" version: "0.6.4+3"
shelf: shelf:
dependency: transitive dependency: transitive
description: description:
name: shelf name: shelf
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.7.5" version: "0.7.7"
shelf_packages_handler: shelf_packages_handler:
dependency: transitive dependency: transitive
description: description:
name: shelf_packages_handler name: shelf_packages_handler
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.4" version: "2.0.0"
shelf_static: shelf_static:
dependency: transitive dependency: transitive
description: description:
@ -713,14 +759,28 @@ packages:
name: sqflite name: sqflite
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.0" version: "1.3.1"
sqflite_common:
dependency: transitive
description:
name: sqflite_common
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2+1"
sqlite3:
dependency: transitive
description:
name: sqlite3
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.4"
stack_trace: stack_trace:
dependency: transitive dependency: transitive
description: description:
name: stack_trace name: stack_trace
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.9.3" version: "1.9.5"
stream_channel: stream_channel:
dependency: transitive dependency: transitive
description: description:
@ -741,7 +801,7 @@ packages:
name: synchronized name: synchronized
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.1" version: "2.2.0+2"
term_glyph: term_glyph:
dependency: transitive dependency: transitive
description: description:
@ -755,28 +815,28 @@ packages:
name: test name: test
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.14.4" version: "1.15.2"
test_api: test_api:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.2.15" version: "0.2.17"
test_core: test_core:
dependency: transitive dependency: transitive
description: description:
name: test_core name: test_core
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.3.4" version: "0.3.10"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
name: typed_data name: typed_data
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.6" version: "1.2.0"
universal_html: universal_html:
dependency: "direct main" dependency: "direct main"
description: description:
@ -790,7 +850,7 @@ packages:
name: universal_io name: universal_io
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.8.6" version: "1.0.1"
unorm_dart: unorm_dart:
dependency: transitive dependency: transitive
description: description:
@ -804,28 +864,35 @@ packages:
name: url_launcher name: url_launcher
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "5.4.1" version: "5.5.0"
url_launcher_linux:
dependency: transitive
description:
name: url_launcher_linux
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.1+1"
url_launcher_macos: url_launcher_macos:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_macos name: url_launcher_macos
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.0.1+2" version: "0.0.1+7"
url_launcher_platform_interface: url_launcher_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_platform_interface name: url_launcher_platform_interface
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.5" version: "1.0.7"
url_launcher_web: url_launcher_web:
dependency: "direct main" dependency: "direct main"
description: description:
name: url_launcher_web name: url_launcher_web
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.0+2" version: "0.1.2"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:
@ -839,14 +906,14 @@ packages:
name: vm_service name: vm_service
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.3.1" version: "4.2.0"
watcher: watcher:
dependency: transitive dependency: transitive
description: description:
name: watcher name: watcher
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.9.7+13" version: "0.9.7+15"
web_socket_channel: web_socket_channel:
dependency: transitive dependency: transitive
description: description:
@ -860,28 +927,35 @@ packages:
name: webkit_inspection_protocol name: webkit_inspection_protocol
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.5.3" version: "0.7.3"
webview_flutter: webview_flutter:
dependency: "direct main" dependency: "direct main"
description: description:
name: webview_flutter name: webview_flutter
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.3.19+9" version: "0.3.22+1"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.0"
xml: xml:
dependency: transitive dependency: transitive
description: description:
name: xml name: xml
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.6.1" version: "4.2.0"
yaml: yaml:
dependency: transitive dependency: transitive
description: description:
name: yaml name: yaml
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.2.0" version: "2.2.1"
zone_local: zone_local:
dependency: transitive dependency: transitive
description: description:
@ -890,5 +964,5 @@ packages:
source: hosted source: hosted
version: "0.1.2" version: "0.1.2"
sdks: sdks:
dart: ">=2.7.0 <3.0.0" dart: ">=2.9.0-14.0.dev <3.0.0"
flutter: ">=1.12.13+hotfix.5 <2.0.0" flutter: ">=1.18.0-6.0.pre <2.0.0"

View file

@ -27,14 +27,17 @@ dependencies:
famedlysdk: famedlysdk:
git: git:
url: https://gitlab.com/famedly/famedlysdk.git url: https://gitlab.com/famedly/famedlysdk.git
ref: 3fae58439bdc2100d26fbfb92a62c7fbb7b48903 ref: 574fe27101bb03c8c18c776e98f7f44668e6d159
localstorage: ^3.0.1+4 localstorage: ^3.0.1+4
bubble: ^1.1.9+1 bubble: ^1.1.9+1
memoryfilepicker: ^0.1.1 memoryfilepicker: ^0.1.1
url_launcher: ^5.4.1 url_launcher: ^5.4.1
url_launcher_web: ^0.1.0 url_launcher_web: ^0.1.0
flutter_advanced_networkimage: any flutter_advanced_networkimage:
git:
url: https://github.com/mchome/flutter_advanced_networkimage
ref: master
firebase_messaging: ^6.0.13 firebase_messaging: ^6.0.13
flutter_local_notifications: ^1.4.3 flutter_local_notifications: ^1.4.3
link_text: ^0.1.1 link_text: ^0.1.1
@ -51,7 +54,10 @@ dependencies:
open_file: ^3.0.1 open_file: ^3.0.1
mime_type: ^0.3.0 mime_type: ^0.3.0
bot_toast: ^3.0.0 bot_toast: ^3.0.0
flutter_matrix_html: ^0.1.2 flutter_matrix_html:
git:
url: https://github.com/Sorunome/flutter_matrix_html
ref: 530df434b50002e04cbad63f53d6f0f5d5adbab5
moor: ^3.0.2 moor: ^3.0.2
random_string: ^2.0.1 random_string: ^2.0.1
flutter_typeahead: ^1.8.1 flutter_typeahead: ^1.8.1