forked from cwtch.im/cwtch-ui
Merge pull request 'Click to scroll on Quoted Message / Shorten Text' (#469) from marcia_fixes into trunk
Reviewed-on: cwtch.im/cwtch-ui#469
This commit is contained in:
commit
e4419366a4
|
@ -0,0 +1,61 @@
|
||||||
|
import 'package:cwtch/third_party/linkify/linkify.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
void modalOpenLink(BuildContext ctx, LinkableElement link) {
|
||||||
|
showModalBottomSheet<void>(
|
||||||
|
context: ctx,
|
||||||
|
builder: (BuildContext bcontext) {
|
||||||
|
return Container(
|
||||||
|
height: 200, // bespoke value courtesy of the [TextField] docs
|
||||||
|
child: Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(30.0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(AppLocalizations.of(bcontext)!.clickableLinksWarning),
|
||||||
|
Flex(direction: Axis.horizontal, mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[
|
||||||
|
Container(
|
||||||
|
margin: EdgeInsets.symmetric(vertical: 20, horizontal: 10),
|
||||||
|
child: ElevatedButton(
|
||||||
|
child: Text(AppLocalizations.of(bcontext)!.clickableLinksCopy, semanticsLabel: AppLocalizations.of(bcontext)!.clickableLinksCopy),
|
||||||
|
onPressed: () {
|
||||||
|
Clipboard.setData(new ClipboardData(text: link.url));
|
||||||
|
|
||||||
|
final snackBar = SnackBar(
|
||||||
|
content: Text(AppLocalizations.of(bcontext)!.copiedToClipboardNotification),
|
||||||
|
);
|
||||||
|
|
||||||
|
Navigator.pop(bcontext);
|
||||||
|
ScaffoldMessenger.of(bcontext).showSnackBar(snackBar);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
margin: EdgeInsets.symmetric(vertical: 20, horizontal: 10),
|
||||||
|
child: ElevatedButton(
|
||||||
|
child: Text(AppLocalizations.of(bcontext)!.clickableLinkOpen, semanticsLabel: AppLocalizations.of(bcontext)!.clickableLinkOpen),
|
||||||
|
onPressed: () async {
|
||||||
|
if (await canLaunch(link.url)) {
|
||||||
|
await launch(link.url);
|
||||||
|
Navigator.pop(bcontext);
|
||||||
|
} else {
|
||||||
|
final snackBar = SnackBar(
|
||||||
|
content: Text(AppLocalizations.of(bcontext)!.clickableLinkError),
|
||||||
|
);
|
||||||
|
ScaffoldMessenger.of(bcontext).showSnackBar(snackBar);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:cwtch/widgets/messagerow.dart';
|
import 'package:cwtch/widgets/messagerow.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
||||||
|
|
||||||
import 'message.dart';
|
import 'message.dart';
|
||||||
import 'messagecache.dart';
|
import 'messagecache.dart';
|
||||||
|
@ -44,6 +45,7 @@ class ContactInfoState extends ChangeNotifier {
|
||||||
late Map<String, GlobalKey<MessageRowState>> keys;
|
late Map<String, GlobalKey<MessageRowState>> keys;
|
||||||
int _newMarkerMsgIndex = -1;
|
int _newMarkerMsgIndex = -1;
|
||||||
late MessageCache messageCache;
|
late MessageCache messageCache;
|
||||||
|
ItemScrollController messageScrollController = new ItemScrollController();
|
||||||
|
|
||||||
// todo: a nicer way to model contacts, groups and other "entities"
|
// todo: a nicer way to model contacts, groups and other "entities"
|
||||||
late bool _isGroup;
|
late bool _isGroup;
|
||||||
|
|
|
@ -8,10 +8,6 @@ import 'package:cwtch/widgets/quotedmessage.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import '../../main.dart';
|
|
||||||
import '../messagecache.dart';
|
|
||||||
import '../profile.dart';
|
|
||||||
|
|
||||||
class QuotedMessageStructure {
|
class QuotedMessageStructure {
|
||||||
final String quotedHash;
|
final String quotedHash;
|
||||||
final String body;
|
final String body;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:cwtch/models/message.dart';
|
import 'package:cwtch/models/message.dart';
|
||||||
import 'package:cwtch/models/messages/malformedmessage.dart';
|
import 'package:cwtch/models/messages/malformedmessage.dart';
|
||||||
import 'package:cwtch/widgets/malformedbubble.dart';
|
import 'package:cwtch/widgets/malformedbubble.dart';
|
||||||
|
@ -19,7 +21,7 @@ class TextMessage extends Message {
|
||||||
return ChangeNotifierProvider.value(
|
return ChangeNotifierProvider.value(
|
||||||
value: this.metadata,
|
value: this.metadata,
|
||||||
builder: (bcontext, child) {
|
builder: (bcontext, child) {
|
||||||
return SelectableText(this.content);
|
return Text(this.content.substring(0, min(this.content.length, 50)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,20 +29,21 @@ class ContactsView extends StatefulWidget {
|
||||||
// selectConversation can be called from anywhere to set the active conversation
|
// selectConversation can be called from anywhere to set the active conversation
|
||||||
void selectConversation(BuildContext context, int handle) {
|
void selectConversation(BuildContext context, int handle) {
|
||||||
// requery instead of using contactinfostate directly because sometimes listview gets confused about data that resorts
|
// requery instead of using contactinfostate directly because sometimes listview gets confused about data that resorts
|
||||||
var initialIndex = Provider.of<ProfileInfoState>(context, listen: false).contactList.getContact(handle)!.unreadMessages;
|
var unread = Provider.of<ProfileInfoState>(context, listen: false).contactList.getContact(handle)!.unreadMessages;
|
||||||
var previouslySelected = Provider.of<AppState>(context, listen: false).selectedConversation;
|
var previouslySelected = Provider.of<AppState>(context, listen: false).selectedConversation;
|
||||||
if (previouslySelected != null) {
|
if (previouslySelected != null) {
|
||||||
Provider.of<ProfileInfoState>(context, listen: false).contactList.getContact(previouslySelected)!.unselected();
|
Provider.of<ProfileInfoState>(context, listen: false).contactList.getContact(previouslySelected)!.unselected();
|
||||||
}
|
}
|
||||||
Provider.of<ProfileInfoState>(context, listen: false).contactList.getContact(handle)!.selected();
|
Provider.of<ProfileInfoState>(context, listen: false).contactList.getContact(handle)!.selected();
|
||||||
// triggers update in Double/TripleColumnView
|
// triggers update in Double/TripleColumnView
|
||||||
Provider.of<AppState>(context, listen: false).initialScrollIndex = initialIndex;
|
Provider.of<AppState>(context, listen: false).initialScrollIndex = unread;
|
||||||
Provider.of<AppState>(context, listen: false).selectedConversation = handle;
|
Provider.of<AppState>(context, listen: false).selectedConversation = handle;
|
||||||
Provider.of<AppState>(context, listen: false).selectedIndex = null;
|
Provider.of<AppState>(context, listen: false).selectedIndex = null;
|
||||||
Provider.of<AppState>(context, listen: false).hoveredIndex = -1;
|
Provider.of<AppState>(context, listen: false).hoveredIndex = -1;
|
||||||
// if in singlepane mode, push to the stack
|
// if in singlepane mode, push to the stack
|
||||||
var isLandscape = Provider.of<AppState>(context, listen: false).isLandscape(context);
|
var isLandscape = Provider.of<AppState>(context, listen: false).isLandscape(context);
|
||||||
if (Provider.of<Settings>(context, listen: false).uiColumns(isLandscape).length == 1) _pushMessageView(context, handle);
|
if (Provider.of<Settings>(context, listen: false).uiColumns(isLandscape).length == 1) _pushMessageView(context, handle);
|
||||||
|
|
||||||
// Set last message seen time in backend
|
// Set last message seen time in backend
|
||||||
Provider.of<FlwtchState>(context, listen: false)
|
Provider.of<FlwtchState>(context, listen: false)
|
||||||
.cwtch
|
.cwtch
|
||||||
|
|
|
@ -42,8 +42,8 @@ class _MessageViewState extends State<MessageView> {
|
||||||
final focusNode = FocusNode();
|
final focusNode = FocusNode();
|
||||||
int selectedContact = -1;
|
int selectedContact = -1;
|
||||||
ItemPositionsListener scrollListener = ItemPositionsListener.create();
|
ItemPositionsListener scrollListener = ItemPositionsListener.create();
|
||||||
ItemScrollController scrollController = ItemScrollController();
|
|
||||||
File? imagePreview;
|
File? imagePreview;
|
||||||
|
bool showDown = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
@ -54,6 +54,12 @@ class _MessageViewState extends State<MessageView> {
|
||||||
Provider.of<AppState>(context, listen: false).initialScrollIndex = 0;
|
Provider.of<AppState>(context, listen: false).initialScrollIndex = 0;
|
||||||
Provider.of<AppState>(context, listen: false).unreadMessagesBelow = false;
|
Provider.of<AppState>(context, listen: false).unreadMessagesBelow = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (scrollListener.itemPositions.value.length != 0 && !scrollListener.itemPositions.value.any((element) => element.index == 0)) {
|
||||||
|
showDown = true;
|
||||||
|
} else {
|
||||||
|
showDown = false;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
@ -128,13 +134,13 @@ class _MessageViewState extends State<MessageView> {
|
||||||
onWillPop: _onWillPop,
|
onWillPop: _onWillPop,
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
backgroundColor: Provider.of<Settings>(context).theme.backgroundMainColor,
|
backgroundColor: Provider.of<Settings>(context).theme.backgroundMainColor,
|
||||||
floatingActionButton: appState.unreadMessagesBelow
|
floatingActionButton: showDown
|
||||||
? FloatingActionButton(
|
? FloatingActionButton(
|
||||||
child: Icon(Icons.arrow_downward, color: Provider.of<Settings>(context).current().defaultButtonTextColor),
|
child: Icon(Icons.arrow_downward, color: Provider.of<Settings>(context).current().defaultButtonTextColor),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Provider.of<AppState>(context, listen: false).initialScrollIndex = 0;
|
Provider.of<AppState>(context, listen: false).initialScrollIndex = 0;
|
||||||
Provider.of<AppState>(context, listen: false).unreadMessagesBelow = false;
|
Provider.of<AppState>(context, listen: false).unreadMessagesBelow = false;
|
||||||
scrollController.scrollTo(index: 0, duration: Duration(milliseconds: 600));
|
Provider.of<ContactInfoState>(context).messageScrollController.scrollTo(index: 0, duration: Duration(milliseconds: 600));
|
||||||
})
|
})
|
||||||
: null,
|
: null,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
|
@ -169,7 +175,11 @@ class _MessageViewState extends State<MessageView> {
|
||||||
]),
|
]),
|
||||||
actions: appBarButtons,
|
actions: appBarButtons,
|
||||||
),
|
),
|
||||||
body: Padding(padding: EdgeInsets.fromLTRB(8.0, 8.0, 8.0, 108.0), child: MessageList(scrollController, scrollListener)),
|
body: Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(8.0, 8.0, 8.0, 108.0),
|
||||||
|
child: MessageList(
|
||||||
|
scrollListener,
|
||||||
|
)),
|
||||||
bottomSheet: _buildComposeBox(),
|
bottomSheet: _buildComposeBox(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,13 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:cwtch/controllers/open_link_modal.dart';
|
||||||
import 'package:cwtch/models/contact.dart';
|
import 'package:cwtch/models/contact.dart';
|
||||||
import 'package:cwtch/models/message.dart';
|
import 'package:cwtch/models/message.dart';
|
||||||
import 'package:cwtch/third_party/linkify/flutter_linkify.dart';
|
import 'package:cwtch/third_party/linkify/flutter_linkify.dart';
|
||||||
import 'package:cwtch/models/profile.dart';
|
import 'package:cwtch/models/profile.dart';
|
||||||
import 'package:cwtch/widgets/malformedbubble.dart';
|
import 'package:cwtch/widgets/malformedbubble.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:intl/intl.dart';
|
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
|
||||||
|
|
||||||
import '../settings.dart';
|
import '../settings.dart';
|
||||||
import 'messagebubbledecorations.dart';
|
import 'messagebubbledecorations.dart';
|
||||||
|
@ -55,7 +52,7 @@ class MessageBubbleState extends State<MessageBubble> {
|
||||||
linkifiers: [UrlLinkifier()],
|
linkifiers: [UrlLinkifier()],
|
||||||
onOpen: showClickableLinks
|
onOpen: showClickableLinks
|
||||||
? (link) {
|
? (link) {
|
||||||
_modalOpenLink(context, link);
|
modalOpenLink(context, link);
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
//key: Key(myKey),
|
//key: Key(myKey),
|
||||||
|
@ -104,59 +101,4 @@ class MessageBubbleState extends State<MessageBubble> {
|
||||||
children: fromMe ? [wdgMessage, wdgDecorations] : [wdgSender, wdgMessage, wdgDecorations])))));
|
children: fromMe ? [wdgMessage, wdgDecorations] : [wdgSender, wdgMessage, wdgDecorations])))));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _modalOpenLink(BuildContext ctx, LinkableElement link) {
|
|
||||||
showModalBottomSheet<void>(
|
|
||||||
context: ctx,
|
|
||||||
builder: (BuildContext bcontext) {
|
|
||||||
return Container(
|
|
||||||
height: 200, // bespoke value courtesy of the [TextField] docs
|
|
||||||
child: Center(
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.all(30.0),
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
Text(AppLocalizations.of(bcontext)!.clickableLinksWarning),
|
|
||||||
Flex(direction: Axis.horizontal, mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[
|
|
||||||
Container(
|
|
||||||
margin: EdgeInsets.symmetric(vertical: 20, horizontal: 10),
|
|
||||||
child: ElevatedButton(
|
|
||||||
child: Text(AppLocalizations.of(bcontext)!.clickableLinksCopy, semanticsLabel: AppLocalizations.of(bcontext)!.clickableLinksCopy),
|
|
||||||
onPressed: () {
|
|
||||||
Clipboard.setData(new ClipboardData(text: link.url));
|
|
||||||
|
|
||||||
final snackBar = SnackBar(
|
|
||||||
content: Text(AppLocalizations.of(bcontext)!.copiedToClipboardNotification),
|
|
||||||
);
|
|
||||||
|
|
||||||
Navigator.pop(bcontext);
|
|
||||||
ScaffoldMessenger.of(bcontext).showSnackBar(snackBar);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
margin: EdgeInsets.symmetric(vertical: 20, horizontal: 10),
|
|
||||||
child: ElevatedButton(
|
|
||||||
child: Text(AppLocalizations.of(bcontext)!.clickableLinkOpen, semanticsLabel: AppLocalizations.of(bcontext)!.clickableLinkOpen),
|
|
||||||
onPressed: () async {
|
|
||||||
if (await canLaunch(link.url)) {
|
|
||||||
await launch(link.url);
|
|
||||||
Navigator.pop(bcontext);
|
|
||||||
} else {
|
|
||||||
final snackBar = SnackBar(
|
|
||||||
content: Text(AppLocalizations.of(bcontext)!.clickableLinkError),
|
|
||||||
);
|
|
||||||
ScaffoldMessenger.of(bcontext).showSnackBar(snackBar);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
],
|
|
||||||
)),
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,8 @@ import '../main.dart';
|
||||||
import '../settings.dart';
|
import '../settings.dart';
|
||||||
|
|
||||||
class MessageList extends StatefulWidget {
|
class MessageList extends StatefulWidget {
|
||||||
ItemScrollController scrollController;
|
|
||||||
ItemPositionsListener scrollListener;
|
ItemPositionsListener scrollListener;
|
||||||
MessageList(this.scrollController, this.scrollListener);
|
MessageList(this.scrollListener);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_MessageListState createState() => _MessageListState();
|
_MessageListState createState() => _MessageListState();
|
||||||
|
@ -30,7 +29,6 @@ class _MessageListState extends State<MessageList> {
|
||||||
MessageCache? cache = Provider.of<ProfileInfoState>(outerContext, listen: false).contactList.getContact(conversationId)?.messageCache;
|
MessageCache? cache = Provider.of<ProfileInfoState>(outerContext, listen: false).contactList.getContact(conversationId)?.messageCache;
|
||||||
ByIndex(0).loadUnsynced(Provider.of<FlwtchState>(context, listen: false).cwtch, Provider.of<AppState>(outerContext, listen: false).selectedProfile!, conversationId, cache!);
|
ByIndex(0).loadUnsynced(Provider.of<FlwtchState>(context, listen: false).cwtch, Provider.of<AppState>(outerContext, listen: false).selectedProfile!, conversationId, cache!);
|
||||||
}
|
}
|
||||||
|
|
||||||
var initi = Provider.of<AppState>(outerContext, listen: false).initialScrollIndex;
|
var initi = Provider.of<AppState>(outerContext, listen: false).initialScrollIndex;
|
||||||
bool isP2P = !Provider.of<ContactInfoState>(context).isGroup;
|
bool isP2P = !Provider.of<ContactInfoState>(context).isGroup;
|
||||||
bool isGroupAndSyncing = Provider.of<ContactInfoState>(context).isGroup == true && Provider.of<ContactInfoState>(context).status == "Authenticated";
|
bool isGroupAndSyncing = Provider.of<ContactInfoState>(context).isGroup == true && Provider.of<ContactInfoState>(context).status == "Authenticated";
|
||||||
|
@ -82,7 +80,7 @@ class _MessageListState extends State<MessageList> {
|
||||||
child: loadMessages
|
child: loadMessages
|
||||||
? ScrollablePositionedList.builder(
|
? ScrollablePositionedList.builder(
|
||||||
itemPositionsListener: widget.scrollListener,
|
itemPositionsListener: widget.scrollListener,
|
||||||
itemScrollController: widget.scrollController,
|
itemScrollController: Provider.of<ContactInfoState>(outerContext).messageScrollController,
|
||||||
initialScrollIndex: initi > 4 ? initi - 4 : 0,
|
initialScrollIndex: initi > 4 ? initi - 4 : 0,
|
||||||
itemCount: Provider.of<ContactInfoState>(outerContext).totalMessages,
|
itemCount: Provider.of<ContactInfoState>(outerContext).totalMessages,
|
||||||
reverse: true, // NOTE: There seems to be a bug in flutter that corrects the mouse wheel scroll, but not the drag direction...
|
reverse: true, // NOTE: There seems to be a bug in flutter that corrects the mouse wheel scroll, but not the drag direction...
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
|
import 'package:cwtch/controllers/open_link_modal.dart';
|
||||||
|
import 'package:cwtch/models/appstate.dart';
|
||||||
import 'package:cwtch/models/contact.dart';
|
import 'package:cwtch/models/contact.dart';
|
||||||
import 'package:cwtch/models/message.dart';
|
import 'package:cwtch/models/message.dart';
|
||||||
import 'package:cwtch/models/profile.dart';
|
import 'package:cwtch/models/profile.dart';
|
||||||
|
import 'package:cwtch/third_party/linkify/flutter_linkify.dart';
|
||||||
|
import 'package:cwtch/views/contactsview.dart';
|
||||||
import 'package:cwtch/widgets/malformedbubble.dart';
|
import 'package:cwtch/widgets/malformedbubble.dart';
|
||||||
import 'package:cwtch/widgets/messageloadingbubble.dart';
|
import 'package:cwtch/widgets/messageloadingbubble.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
@ -43,12 +47,29 @@ class QuotedMessageBubbleState extends State<QuotedMessageBubble> {
|
||||||
var wdgSender = SelectableText(senderDisplayStr,
|
var wdgSender = SelectableText(senderDisplayStr,
|
||||||
style: TextStyle(fontSize: 9.0, color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeTextColor : Provider.of<Settings>(context).theme.messageFromOtherTextColor));
|
style: TextStyle(fontSize: 9.0, color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeTextColor : Provider.of<Settings>(context).theme.messageFromOtherTextColor));
|
||||||
|
|
||||||
var wdgMessage = SelectableText(
|
var showClickableLinks = Provider.of<Settings>(context).isExperimentEnabled(ClickableLinksExperiment);
|
||||||
widget.body + '\u202F',
|
var formatMessages = Provider.of<Settings>(context).isExperimentEnabled(FormattingExperiment);
|
||||||
|
|
||||||
|
var wdgMessage = SelectableLinkify(
|
||||||
|
text: widget.body + '\u202F',
|
||||||
|
// TODO: onOpen breaks the "selectable" functionality. Maybe something to do with gesture handler?
|
||||||
|
options: LinkifyOptions(messageFormatting: formatMessages, parseLinks: showClickableLinks, looseUrl: true, defaultToHttps: true),
|
||||||
|
linkifiers: [UrlLinkifier()],
|
||||||
|
onOpen: showClickableLinks
|
||||||
|
? (link) {
|
||||||
|
modalOpenLink(context, link);
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
//key: Key(myKey),
|
||||||
focusNode: _focus,
|
focusNode: _focus,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeTextColor : Provider.of<Settings>(context).theme.messageFromOtherTextColor,
|
color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeTextColor : Provider.of<Settings>(context).theme.messageFromOtherTextColor,
|
||||||
),
|
),
|
||||||
|
linkStyle: TextStyle(color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeTextColor : Provider.of<Settings>(context).theme.messageFromOtherTextColor),
|
||||||
|
codeStyle: TextStyle(
|
||||||
|
// note: these colors are flipped
|
||||||
|
color: fromMe ? Provider.of<Settings>(context).theme.messageFromOtherTextColor : Provider.of<Settings>(context).theme.messageFromMeTextColor,
|
||||||
|
backgroundColor: fromMe ? Provider.of<Settings>(context).theme.messageFromOtherBackgroundColor : Provider.of<Settings>(context).theme.messageFromMeBackgroundColor),
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
textWidthBasis: TextWidthBasis.longestLine,
|
textWidthBasis: TextWidthBasis.longestLine,
|
||||||
);
|
);
|
||||||
|
@ -61,14 +82,23 @@ class QuotedMessageBubbleState extends State<QuotedMessageBubble> {
|
||||||
var qMessage = (snapshot.data! as Message);
|
var qMessage = (snapshot.data! as Message);
|
||||||
// Swap the background color for quoted tweets..
|
// Swap the background color for quoted tweets..
|
||||||
var qTextColor = fromMe ? Provider.of<Settings>(context).theme.messageFromOtherTextColor : Provider.of<Settings>(context).theme.messageFromMeTextColor;
|
var qTextColor = fromMe ? Provider.of<Settings>(context).theme.messageFromOtherTextColor : Provider.of<Settings>(context).theme.messageFromMeTextColor;
|
||||||
return Container(
|
return MouseRegion(
|
||||||
margin: EdgeInsets.all(5),
|
cursor: SystemMouseCursors.click,
|
||||||
padding: EdgeInsets.all(5),
|
child: GestureDetector(
|
||||||
color: fromMe ? Provider.of<Settings>(context).theme.messageFromOtherBackgroundColor : Provider.of<Settings>(context).theme.messageFromMeBackgroundColor,
|
onTap: () {
|
||||||
child: Wrap(runAlignment: WrapAlignment.spaceEvenly, alignment: WrapAlignment.spaceEvenly, runSpacing: 1.0, crossAxisAlignment: WrapCrossAlignment.center, children: [
|
var index = Provider.of<ContactInfoState>(context, listen: false).messageCache.cacheByHash[qMessage.getMetadata().contenthash];
|
||||||
Center(widthFactor: 1, child: Padding(padding: EdgeInsets.all(10.0), child: Icon(Icons.reply, size: 32, color: qTextColor))),
|
var totalMessages = Provider.of<ContactInfoState>(context, listen: false).totalMessages;
|
||||||
Center(widthFactor: 1.0, child: DefaultTextStyle(child: qMessage.getPreviewWidget(context), style: TextStyle(color: qTextColor)))
|
// we have to reverse here because the list itself is reversed...
|
||||||
]));
|
Provider.of<ContactInfoState>(context).messageScrollController.scrollTo(index: totalMessages - index!, duration: Duration(milliseconds: 100));
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
margin: EdgeInsets.all(5),
|
||||||
|
padding: EdgeInsets.all(5),
|
||||||
|
color: fromMe ? Provider.of<Settings>(context).theme.messageFromOtherBackgroundColor : Provider.of<Settings>(context).theme.messageFromMeBackgroundColor,
|
||||||
|
child: Wrap(runAlignment: WrapAlignment.spaceEvenly, alignment: WrapAlignment.spaceEvenly, runSpacing: 1.0, crossAxisAlignment: WrapCrossAlignment.center, children: [
|
||||||
|
Center(widthFactor: 1, child: Padding(padding: EdgeInsets.all(10.0), child: Icon(Icons.reply, size: 32, color: qTextColor))),
|
||||||
|
Center(widthFactor: 1.0, child: DefaultTextStyle(child: qMessage.getPreviewWidget(context), style: TextStyle(color: qTextColor)))
|
||||||
|
]))));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e);
|
print(e);
|
||||||
return MalformedBubble();
|
return MalformedBubble();
|
||||||
|
|
Loading…
Reference in New Issue