Malformed Message Warning
continuous-integration/drone/pr Build is passing
Details
continuous-integration/drone/pr Build is passing
Details
This commit is contained in:
parent
a0a0a8db99
commit
1497996bec
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
|
@ -0,0 +1,71 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 25.2.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
version="1.1"
|
||||||
|
id="Layer_1"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
style="enable-background:new 0 0 24 24;"
|
||||||
|
xml:space="preserve"
|
||||||
|
sodipodi:docname="broken_heart_24.svg"
|
||||||
|
inkscape:export-filename="/home/sarah/AndroidStudioProjects/flutter_app/assets/core/broken_heart_24.png"
|
||||||
|
inkscape:export-xdpi="1280"
|
||||||
|
inkscape:export-ydpi="1280"
|
||||||
|
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"><metadata
|
||||||
|
id="metadata19"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs17" /><sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1015"
|
||||||
|
id="namedview15"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="9.8333333"
|
||||||
|
inkscape:cx="-6.344409"
|
||||||
|
inkscape:cy="12.067375"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="Layer_1" />
|
||||||
|
<path
|
||||||
|
d="M16.5,3c-1.7,0-3.4,0.8-4.5,2.1C10.9,3.8,9.2,3,7.5,3C4.8,3,2.6,4.9,2.1,7.4C2,7.7,12,12.5,12,12.5L16.5,3z"
|
||||||
|
id="path2"
|
||||||
|
style="fill:#ffffff" />
|
||||||
|
<path
|
||||||
|
d="M7.5,17.3c0.9,0.9,1.9,1.8,3,2.8l1.5,1.3l1.5-1.3c0.2-0.2,0.5-0.4,0.7-0.7L12,12.5L7.5,17.3z"
|
||||||
|
id="path4"
|
||||||
|
style="fill:#ffffff" />
|
||||||
|
<path
|
||||||
|
d="M12,12.5l5.5,3.7c2.5-2.5,4.1-4.6,4.4-7C22,9,12,12.5,12,12.5z"
|
||||||
|
id="path6"
|
||||||
|
style="fill:#ffffff" />
|
||||||
|
<path
|
||||||
|
d="M23,6.8c-0.2-1.8-1.2-3.4-2.8-4.2l-7.2,8.8L23,6.8z"
|
||||||
|
id="path8"
|
||||||
|
style="fill:#ffffff" />
|
||||||
|
<path
|
||||||
|
d="M0.7,9.1c0.1,2.6,1.9,4.9,4.8,7.7l5.3-4L0.7,9.1z"
|
||||||
|
id="path10"
|
||||||
|
style="fill:#ffffff" />
|
||||||
|
<path
|
||||||
|
d="M16.4,22.3c1.2-1.1,2.4-2.2,3.4-3.1l-5.5-3.7L16.4,22.3z"
|
||||||
|
id="path12"
|
||||||
|
style="fill:#ffffff" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.4 KiB |
|
@ -363,6 +363,7 @@ class MessageState extends ChangeNotifier {
|
||||||
bool _ackd = false;
|
bool _ackd = false;
|
||||||
bool _error = false;
|
bool _error = false;
|
||||||
bool _loaded = false;
|
bool _loaded = false;
|
||||||
|
bool _malformed = false;
|
||||||
|
|
||||||
MessageState({
|
MessageState({
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
|
@ -379,6 +380,7 @@ class MessageState extends ChangeNotifier {
|
||||||
get timestamp => this._timestamp;
|
get timestamp => this._timestamp;
|
||||||
get ackd => this._ackd;
|
get ackd => this._ackd;
|
||||||
get error => this._error;
|
get error => this._error;
|
||||||
|
get malformed => this._malformed;
|
||||||
get senderOnion => this._senderOnion;
|
get senderOnion => this._senderOnion;
|
||||||
get senderImage => this._senderImage;
|
get senderImage => this._senderImage;
|
||||||
get loaded => this._loaded;
|
get loaded => this._loaded;
|
||||||
|
@ -399,50 +401,54 @@ class MessageState extends ChangeNotifier {
|
||||||
|
|
||||||
void tryLoad(BuildContext context) {
|
void tryLoad(BuildContext context) {
|
||||||
Provider.of<FlwtchState>(context, listen: false).cwtch.GetMessage(profileOnion, contactHandle, messageIndex).then((jsonMessage) {
|
Provider.of<FlwtchState>(context, listen: false).cwtch.GetMessage(profileOnion, contactHandle, messageIndex).then((jsonMessage) {
|
||||||
dynamic messageWrapper = jsonDecode(jsonMessage);
|
try {
|
||||||
if (messageWrapper['Message'] == null || messageWrapper['Message'] == '' || messageWrapper['Message'] == '{}') {
|
dynamic messageWrapper = jsonDecode(jsonMessage);
|
||||||
//todo: remove once sent group messages are prestored
|
if (messageWrapper['Message'] == null || messageWrapper['Message'] == '' || messageWrapper['Message'] == '{}') {
|
||||||
Future.delayed(const Duration(milliseconds: 2), () {
|
this._senderOnion = profileOnion;
|
||||||
tryLoad(context);
|
//todo: remove once sent group messages are prestored
|
||||||
});
|
Future.delayed(const Duration(milliseconds: 2), () {
|
||||||
return;
|
tryLoad(context);
|
||||||
}
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dynamic message = jsonDecode(messageWrapper['Message']);
|
||||||
|
this._message = message['d'];
|
||||||
|
this._overlay = int.parse(message['o'].toString());
|
||||||
|
this._timestamp = DateTime.tryParse(messageWrapper['Timestamp']);
|
||||||
|
this._senderOnion = messageWrapper['PeerID'];
|
||||||
|
this._senderImage = messageWrapper['ContactImage'];
|
||||||
|
|
||||||
dynamic message = jsonDecode(messageWrapper['Message']);
|
// If this is a group, store the signature
|
||||||
this._message = message['d'];
|
if (contactHandle.length == 32) {
|
||||||
this._overlay = int.parse(message['o'].toString());
|
this._signature = messageWrapper['Signature'];
|
||||||
this._timestamp = DateTime.tryParse(messageWrapper['Timestamp']);
|
}
|
||||||
this._senderOnion = messageWrapper['PeerID'];
|
|
||||||
this._senderImage = messageWrapper['ContactImage'];
|
|
||||||
|
|
||||||
// If this is a group, store the signature
|
// if this is an invite, get the contact handle
|
||||||
if (contactHandle.length == 32) {
|
if (this.isInvite) {
|
||||||
this._signature = messageWrapper['Signature'];
|
if (message['d'].toString().length == 56) {
|
||||||
}
|
this._inviteTarget = message['d'];
|
||||||
|
var targetContact = Provider.of<ProfileInfoState>(context).contactList.getContact(this._inviteTarget);
|
||||||
// if this is an invite, get the contact handle
|
this._inviteNick = targetContact == null ? message['d'] : targetContact.nickname;
|
||||||
if (this.isInvite) {
|
} else {
|
||||||
if (message['d'].toString().length == 56) {
|
var parts = message['d'].toString().split("||");
|
||||||
this._inviteTarget = message['d'];
|
if (parts.length == 2) {
|
||||||
var targetContact = Provider.of<ProfileInfoState>(context).contactList.getContact(this._inviteTarget);
|
print("jsondecoding: " + utf8.fuse(base64).decode(parts[1].substring(5)));
|
||||||
this._inviteNick = targetContact == null ? message['d'] : targetContact.nickname;
|
var jsonObj = jsonDecode(utf8.fuse(base64).decode(parts[1].substring(5)));
|
||||||
} else {
|
this._inviteTarget = jsonObj['GroupID'];
|
||||||
var parts = message['d'].toString().split("||");
|
this._inviteNick = jsonObj['GroupName'];
|
||||||
if (parts.length == 2) {
|
}
|
||||||
print("jsondecoding: "+utf8.fuse(base64).decode(parts[1].substring(5)));
|
|
||||||
var jsonObj = jsonDecode(utf8.fuse(base64).decode(parts[1].substring(5)));
|
|
||||||
this._inviteTarget = jsonObj['GroupID'];
|
|
||||||
this._inviteNick = jsonObj['GroupName'];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
this._loaded = true;
|
this._loaded = true;
|
||||||
|
|
||||||
//update ackd and error last as they are changenotified
|
//update ackd and error last as they are changenotified
|
||||||
this.ackd = messageWrapper['Acknowledged'];
|
this.ackd = messageWrapper['Acknowledged'];
|
||||||
if (messageWrapper['Error'] != null) {
|
if (messageWrapper['Error'] != null) {
|
||||||
this.error = true;
|
this.error = true;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
this._malformed = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,18 +81,16 @@ class _MessageViewState extends State<MessageView> {
|
||||||
|
|
||||||
void _sendMessage([String ignoredParam]) {
|
void _sendMessage([String ignoredParam]) {
|
||||||
ChatMessage cm = new ChatMessage(o: 1, d: ctrlrCompose.value.text);
|
ChatMessage cm = new ChatMessage(o: 1, d: ctrlrCompose.value.text);
|
||||||
Provider.of<FlwtchState>(context, listen: false).cwtch.SendMessage(
|
Provider.of<FlwtchState>(context, listen: false)
|
||||||
Provider.of<ContactInfoState>(context, listen: false).profileOnion,
|
.cwtch
|
||||||
Provider.of<ContactInfoState>(context, listen: false).onion,
|
.SendMessage(Provider.of<ContactInfoState>(context, listen: false).profileOnion, Provider.of<ContactInfoState>(context, listen: false).onion, jsonEncode(cm));
|
||||||
jsonEncode(cm));
|
|
||||||
_sendMessageHelper();
|
_sendMessageHelper();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _sendInvitation([String ignoredParam]) {
|
void _sendInvitation([String ignoredParam]) {
|
||||||
Provider.of<FlwtchState>(context, listen: false).cwtch.SendInvitation(
|
Provider.of<FlwtchState>(context, listen: false)
|
||||||
Provider.of<ContactInfoState>(context, listen: false).profileOnion,
|
.cwtch
|
||||||
Provider.of<ContactInfoState>(context, listen: false).onion,
|
.SendInvitation(Provider.of<ContactInfoState>(context, listen: false).profileOnion, Provider.of<ContactInfoState>(context, listen: false).onion, this.selectedContact);
|
||||||
this.selectedContact);
|
|
||||||
_sendMessageHelper();
|
_sendMessageHelper();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,23 +119,25 @@ class _MessageViewState extends State<MessageView> {
|
||||||
textInputAction: TextInputAction.send,
|
textInputAction: TextInputAction.send,
|
||||||
onSubmitted: _sendMessage,
|
onSubmitted: _sendMessage,
|
||||||
)),
|
)),
|
||||||
Column(children:[SizedBox(
|
Column(children: [
|
||||||
width: 100,
|
SizedBox(
|
||||||
height: 50,
|
width: 100,
|
||||||
child: Padding(
|
height: 50,
|
||||||
padding: EdgeInsets.fromLTRB(2, 2, 2, 2),
|
child: Padding(
|
||||||
child: ElevatedButton(
|
padding: EdgeInsets.fromLTRB(2, 2, 2, 2),
|
||||||
child: Icon(Icons.send, size: 24, color: Provider.of<Settings>(context).theme.mainTextColor()),
|
child: ElevatedButton(
|
||||||
style: ButtonStyle(
|
child: Icon(Icons.send, size: 24, color: Provider.of<Settings>(context).theme.mainTextColor()),
|
||||||
fixedSize: MaterialStateProperty.all(Size(86, 50)),
|
style: ButtonStyle(
|
||||||
backgroundColor: MaterialStateProperty.all(Provider.of<Settings>(context).theme.defaultButtonColor()),
|
fixedSize: MaterialStateProperty.all(Size(86, 50)),
|
||||||
),
|
backgroundColor: MaterialStateProperty.all(Provider.of<Settings>(context).theme.defaultButtonColor()),
|
||||||
onPressed: _sendMessage,
|
),
|
||||||
))),
|
onPressed: _sendMessage,
|
||||||
SizedBox(
|
))),
|
||||||
width: 86, height: 40,
|
SizedBox(
|
||||||
child: IconButton(icon: Icon(Icons.insert_invitation, size: 12, color: Provider.of<Settings>(context).theme.mainTextColor()), onPressed: () => _modalSendInvitation(context))
|
width: 86,
|
||||||
),])
|
height: 40,
|
||||||
|
child: IconButton(icon: Icon(Icons.insert_invitation, size: 12, color: Provider.of<Settings>(context).theme.mainTextColor()), onPressed: () => _modalSendInvitation(context))),
|
||||||
|
])
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -165,10 +165,16 @@ class _MessageViewState extends State<MessageView> {
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
ChangeNotifierProvider.value(value: Provider.of<ProfileInfoState>(ctx, listen: false), child: DropdownContacts(onChanged: (newVal) {
|
ChangeNotifierProvider.value(
|
||||||
setState((){ this.selectedContact = newVal; });
|
value: Provider.of<ProfileInfoState>(ctx, listen: false),
|
||||||
})),
|
child: DropdownContacts(onChanged: (newVal) {
|
||||||
SizedBox(height: 20,),
|
setState(() {
|
||||||
|
this.selectedContact = newVal;
|
||||||
|
});
|
||||||
|
})),
|
||||||
|
SizedBox(
|
||||||
|
height: 20,
|
||||||
|
),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
child: Text(AppLocalizations.of(bcontext).inviteBtn, semanticsLabel: AppLocalizations.of(bcontext).inviteBtn),
|
child: Text(AppLocalizations.of(bcontext).inviteBtn, semanticsLabel: AppLocalizations.of(bcontext).inviteBtn),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
|
|
@ -8,7 +8,9 @@ import '../model.dart';
|
||||||
// Displays nicknames to UI but uses handles as values
|
// Displays nicknames to UI but uses handles as values
|
||||||
// Pass an onChanged handler to access value
|
// Pass an onChanged handler to access value
|
||||||
class DropdownContacts extends StatefulWidget {
|
class DropdownContacts extends StatefulWidget {
|
||||||
DropdownContacts({this.onChanged,});
|
DropdownContacts({
|
||||||
|
this.onChanged,
|
||||||
|
});
|
||||||
final Function(dynamic) onChanged;
|
final Function(dynamic) onChanged;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -20,15 +22,18 @@ class _DropdownContactsState extends State<DropdownContacts> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return DropdownButton(value: this.selected, items: Provider.of<ProfileInfoState>(context, listen: false).contactList.contacts.map<DropdownMenuItem<String>>((ContactInfoState contact) {
|
return DropdownButton(
|
||||||
return DropdownMenuItem<String>(value: contact.onion, child: Text(contact.nickname??contact.onion));
|
value: this.selected,
|
||||||
}).toList(), onChanged: (newVal) {
|
items: Provider.of<ProfileInfoState>(context, listen: false).contactList.contacts.map<DropdownMenuItem<String>>((ContactInfoState contact) {
|
||||||
setState(() {
|
return DropdownMenuItem<String>(value: contact.onion, child: Text(contact.nickname ?? contact.onion));
|
||||||
this.selected = newVal;
|
}).toList(),
|
||||||
});
|
onChanged: (newVal) {
|
||||||
if (widget.onChanged != null) {
|
setState(() {
|
||||||
widget.onChanged(newVal);
|
this.selected = newVal;
|
||||||
}
|
});
|
||||||
});
|
if (widget.onChanged != null) {
|
||||||
|
widget.onChanged(newVal);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,27 +43,33 @@ class InvitationBubbleState extends State<InvitationBubble> {
|
||||||
senderDisplayStr = contact.nickname ?? contact.onion;
|
senderDisplayStr = contact.nickname ?? contact.onion;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var wdgSender = Center(widthFactor:1, child: SelectableText(senderDisplayStr + '\u202F',
|
var wdgSender = Center(
|
||||||
style: TextStyle(fontSize: 9.0, color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeTextColor() : Provider.of<Settings>(context).theme.messageFromOtherTextColor())));
|
widthFactor: 1,
|
||||||
|
child: SelectableText(senderDisplayStr + '\u202F',
|
||||||
|
style: TextStyle(fontSize: 9.0, color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeTextColor() : Provider.of<Settings>(context).theme.messageFromOtherTextColor())));
|
||||||
|
|
||||||
// todo: translations
|
// todo: translations
|
||||||
var messageStr = "";
|
var messageStr = "";
|
||||||
if (fromMe) {
|
if (fromMe) {
|
||||||
//todo: get group name?
|
//todo: get group name?
|
||||||
messageStr = "You sent an invitation for "+(isGroup ? "a group" : Provider.of<MessageState>(context).message ?? "");
|
messageStr = "You sent an invitation for " + (isGroup ? "a group" : Provider.of<MessageState>(context).message ?? "");
|
||||||
} else {
|
} else {
|
||||||
messageStr = (isGroup ? "You have been invited to join "+(Provider.of<MessageState>(context).inviteNick??"") : "This is a contact suggestion for:") + "\n" + (Provider.of<MessageState>(context).inviteTarget ?? "");
|
messageStr = (isGroup ? "You have been invited to join " + (Provider.of<MessageState>(context).inviteNick ?? "") : "This is a contact suggestion for:") +
|
||||||
|
"\n" +
|
||||||
|
(Provider.of<MessageState>(context).inviteTarget ?? "");
|
||||||
}
|
}
|
||||||
var wdgMessage = Center(widthFactor:1, child: SelectableText(
|
var wdgMessage = Center(
|
||||||
messageStr + '\u202F',
|
widthFactor: 1,
|
||||||
key: Key(myKey),
|
child: SelectableText(
|
||||||
focusNode: _focus,
|
messageStr + '\u202F',
|
||||||
style: TextStyle(
|
key: Key(myKey),
|
||||||
color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeTextColor() : Provider.of<Settings>(context).theme.messageFromOtherTextColor(),
|
focusNode: _focus,
|
||||||
),
|
style: TextStyle(
|
||||||
textAlign: TextAlign.left,
|
color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeTextColor() : Provider.of<Settings>(context).theme.messageFromOtherTextColor(),
|
||||||
textWidthBasis: TextWidthBasis.longestLine,
|
),
|
||||||
));
|
textAlign: TextAlign.left,
|
||||||
|
textWidthBasis: TextWidthBasis.longestLine,
|
||||||
|
));
|
||||||
|
|
||||||
Widget wdgDecorations;
|
Widget wdgDecorations;
|
||||||
if (fromMe) {
|
if (fromMe) {
|
||||||
|
@ -72,15 +78,14 @@ class InvitationBubbleState extends State<InvitationBubble> {
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Text(prettyDate, style: TextStyle(
|
Text(prettyDate,
|
||||||
fontSize: 9.0,
|
style: TextStyle(fontSize: 9.0, 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()
|
textAlign: fromMe ? TextAlign.right : TextAlign.left),
|
||||||
), textAlign: fromMe ? TextAlign.right : TextAlign.left),
|
|
||||||
!fromMe
|
!fromMe
|
||||||
? SizedBox(width: 1, height: 1)
|
? SizedBox(width: 1, height: 1)
|
||||||
: Provider.of<MessageState>(context).ackd
|
: Provider.of<MessageState>(context).ackd
|
||||||
? Icon(Icons.check_circle_outline, color: Provider.of<Settings>(context).theme.messageFromMeTextColor(), size: 12)
|
? Icon(Icons.check_circle_outline, color: Provider.of<Settings>(context).theme.messageFromMeTextColor(), size: 12)
|
||||||
: Icon(Icons.hourglass_bottom_outlined, color: Provider.of<Settings>(context).theme.messageFromMeTextColor(), size: 12)
|
: Icon(Icons.hourglass_bottom_outlined, color: Provider.of<Settings>(context).theme.messageFromMeTextColor(), size: 12)
|
||||||
],
|
],
|
||||||
));
|
));
|
||||||
} else if (isAccepted) {
|
} else if (isAccepted) {
|
||||||
|
@ -88,10 +93,12 @@ class InvitationBubbleState extends State<InvitationBubble> {
|
||||||
} else if (this.rejected) {
|
} else if (this.rejected) {
|
||||||
wdgDecorations = Text("Rejected.");
|
wdgDecorations = Text("Rejected.");
|
||||||
} else {
|
} else {
|
||||||
wdgDecorations = Center(widthFactor:1,child:Row(children: [
|
wdgDecorations = Center(
|
||||||
Padding(padding: EdgeInsets.all(5), child: TextButton(child: Text("Reject"), onPressed: _btnReject)),
|
widthFactor: 1,
|
||||||
Padding(padding: EdgeInsets.all(5), child: TextButton(child: Text("Accept"), onPressed: _btnAccept)),
|
child: Row(children: [
|
||||||
]));
|
Padding(padding: EdgeInsets.all(5), child: TextButton(child: Text("Reject"), onPressed: _btnReject)),
|
||||||
|
Padding(padding: EdgeInsets.all(5), child: TextButton(child: Text("Accept"), onPressed: _btnAccept)),
|
||||||
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
return LayoutBuilder(builder: (context, constraints) {
|
return LayoutBuilder(builder: (context, constraints) {
|
||||||
|
@ -110,21 +117,26 @@ class InvitationBubbleState extends State<InvitationBubble> {
|
||||||
bottomRight: fromMe ? Radius.zero : Radius.circular(borderRadiousEh),
|
bottomRight: fromMe ? Radius.zero : Radius.circular(borderRadiousEh),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Center(widthFactor: 1.0,child:Padding(
|
child: Center(
|
||||||
padding: EdgeInsets.all(9.0),
|
widthFactor: 1.0,
|
||||||
child: Row(mainAxisSize: MainAxisSize.min, children: [Center(widthFactor: 1,child: Padding(padding:EdgeInsets.all(4), child:Icon(Icons.group_add, size: 32))),
|
child: Padding(
|
||||||
Center(widthFactor: 1.0,child: Column(
|
padding: EdgeInsets.all(9.0),
|
||||||
crossAxisAlignment: fromMe ? CrossAxisAlignment.end : CrossAxisAlignment.start,
|
child: Row(mainAxisSize: MainAxisSize.min, children: [
|
||||||
mainAxisAlignment: fromMe ? MainAxisAlignment.end : MainAxisAlignment.start,
|
Center(widthFactor: 1, child: Padding(padding: EdgeInsets.all(4), child: Icon(Icons.group_add, size: 32))),
|
||||||
mainAxisSize: MainAxisSize.min,
|
Center(
|
||||||
children: fromMe ? [wdgMessage, wdgDecorations] : [wdgSender, wdgMessage, wdgDecorations])),
|
widthFactor: 1.0,
|
||||||
])))));
|
child: Column(
|
||||||
|
crossAxisAlignment: fromMe ? CrossAxisAlignment.end : CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: fromMe ? MainAxisAlignment.end : MainAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: fromMe ? [wdgMessage, wdgDecorations] : [wdgSender, wdgMessage, wdgDecorations])),
|
||||||
|
])))));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _btnReject() {
|
void _btnReject() {
|
||||||
//todo: how should we track inline invite rejections?
|
//todo: how should we track inline invite rejections?
|
||||||
setState(()=>this.rejected = true);
|
setState(() => this.rejected = true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _btnAccept() {
|
void _btnAccept() {
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:ffi';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import '../settings.dart';
|
||||||
|
|
||||||
|
final Color malformedColor = Color(0xFFE85DA1);
|
||||||
|
|
||||||
|
// MalformedBubble is displayed in the case of a malformed message
|
||||||
|
class MalformedBubble extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
MalformedBubbleState createState() => MalformedBubbleState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class MalformedBubbleState extends State<MalformedBubble> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return LayoutBuilder(builder: (context, constraints) {
|
||||||
|
return Center(
|
||||||
|
widthFactor: 1.0,
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: malformedColor,
|
||||||
|
border: Border.all(color: malformedColor, width: 1),
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft: Radius.zero,
|
||||||
|
topRight: Radius.zero,
|
||||||
|
bottomLeft: Radius.zero,
|
||||||
|
bottomRight: Radius.zero,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Center(
|
||||||
|
widthFactor: 1.0,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(9.0),
|
||||||
|
child: Row(mainAxisSize: MainAxisSize.min, children: [
|
||||||
|
Center(
|
||||||
|
widthFactor: 1,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(4),
|
||||||
|
child: Image(
|
||||||
|
image: AssetImage("assets/core/broken_heart_24.png"),
|
||||||
|
filterQuality: FilterQuality.medium,
|
||||||
|
// We need some theme specific blending here...we might want to consider making this a theme level attribute
|
||||||
|
colorBlendMode: BlendMode.srcIn,
|
||||||
|
color: Provider.of<Settings>(context).theme.mainTextColor(),
|
||||||
|
isAntiAlias: false,
|
||||||
|
width: 32,
|
||||||
|
height: 32))),
|
||||||
|
Center(
|
||||||
|
widthFactor: 1.0,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [Text("Malformed Message")],
|
||||||
|
))
|
||||||
|
])))));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,6 +13,6 @@ class MessageLoadingBubble extends StatefulWidget {
|
||||||
class MessageLoadingBubbleState extends State<MessageLoadingBubble> {
|
class MessageLoadingBubbleState extends State<MessageLoadingBubble> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Center(child:Row(children:[SizedBox(width:40, height:100, child: Text(""))]));
|
return Center(child: Row(children: [SizedBox(width: 40, height: 100, child: Text(""))]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import '../main.dart';
|
||||||
import '../model.dart';
|
import '../model.dart';
|
||||||
import '../settings.dart';
|
import '../settings.dart';
|
||||||
import 'invitationbubble.dart';
|
import 'invitationbubble.dart';
|
||||||
|
import 'malformedbubble.dart';
|
||||||
import 'messagebubble.dart';
|
import 'messagebubble.dart';
|
||||||
import 'messageloadingbubble.dart';
|
import 'messageloadingbubble.dart';
|
||||||
|
|
||||||
|
@ -23,8 +24,17 @@ class _MessageRowState extends State<MessageRow> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var fromMe = Provider.of<MessageState>(context).senderOnion == Provider.of<ProfileInfoState>(context).onion;
|
var fromMe = Provider.of<MessageState>(context).senderOnion == Provider.of<ProfileInfoState>(context).onion;
|
||||||
|
var malformed = Provider.of<MessageState>(context).malformed;
|
||||||
|
|
||||||
Widget wdgBubble = Flexible(flex: 3, fit: FlexFit.loose, child: Provider.of<MessageState>(context).loaded == true ? widgetForOverlay(Provider.of<MessageState>(context).overlay) : MessageLoadingBubble());
|
// If the message is malformed then override fromme as we can't trust it
|
||||||
|
if (malformed) {
|
||||||
|
fromMe = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget wdgBubble = Flexible(
|
||||||
|
flex: 3,
|
||||||
|
fit: FlexFit.loose,
|
||||||
|
child: malformed ? MalformedBubble() : (Provider.of<MessageState>(context).loaded == true ? widgetForOverlay(Provider.of<MessageState>(context).overlay) : MessageLoadingBubble()));
|
||||||
Widget wdgIcons = Icon(Icons.delete_forever_outlined, color: Provider.of<Settings>(context).theme.dropShadowColor());
|
Widget wdgIcons = Icon(Icons.delete_forever_outlined, color: Provider.of<Settings>(context).theme.dropShadowColor());
|
||||||
Widget wdgSpacer = Expanded(child: SizedBox(width: 60, height: 10));
|
Widget wdgSpacer = Expanded(child: SizedBox(width: 60, height: 10));
|
||||||
var widgetRow = <Widget>[];
|
var widgetRow = <Widget>[];
|
||||||
|
@ -38,12 +48,14 @@ class _MessageRowState extends State<MessageRow> {
|
||||||
} else {
|
} else {
|
||||||
var contact = Provider.of<ContactInfoState>(context);
|
var contact = Provider.of<ContactInfoState>(context);
|
||||||
Widget wdgPortrait = GestureDetector(
|
Widget wdgPortrait = GestureDetector(
|
||||||
onTap: _btnAdd,
|
onTap: _btnAdd,
|
||||||
child: ProfileImage(
|
child: Padding(
|
||||||
diameter: 48.0,
|
padding: EdgeInsets.all(4.0),
|
||||||
imagePath: Provider.of<MessageState>(context).senderImage ?? contact.imagePath,
|
child: ProfileImage(
|
||||||
//maskOut: contact.status != "Authenticated",
|
diameter: 48.0,
|
||||||
border: contact.status == "Authenticated" ? Provider.of<Settings>(context).theme.portraitOnlineBorderColor() : Provider.of<Settings>(context).theme.portraitOfflineBorderColor()));
|
imagePath: Provider.of<MessageState>(context).senderImage ?? contact.imagePath,
|
||||||
|
//maskOut: contact.status != "Authenticated",
|
||||||
|
border: contact.status == "Authenticated" ? Provider.of<Settings>(context).theme.portraitOnlineBorderColor() : Provider.of<Settings>(context).theme.portraitOfflineBorderColor())));
|
||||||
|
|
||||||
widgetRow = <Widget>[
|
widgetRow = <Widget>[
|
||||||
wdgPortrait,
|
wdgPortrait,
|
||||||
|
@ -58,9 +70,11 @@ class _MessageRowState extends State<MessageRow> {
|
||||||
|
|
||||||
Widget widgetForOverlay(int o) {
|
Widget widgetForOverlay(int o) {
|
||||||
switch (o) {
|
switch (o) {
|
||||||
case 1: return MessageBubble();
|
case 1:
|
||||||
|
return MessageBubble();
|
||||||
case 100:
|
case 100:
|
||||||
case 101: return InvitationBubble();
|
case 101:
|
||||||
|
return InvitationBubble();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue