forked from cwtch.im/cwtch-ui
moar fileshare plz
This commit is contained in:
parent
cb3c161277
commit
8fe577afd4
|
@ -194,6 +194,11 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) :
|
||||||
Log.i("FlwtchWorker::DownloadFile", "DownloadFile("+filepath+", "+manifestpath+")")
|
Log.i("FlwtchWorker::DownloadFile", "DownloadFile("+filepath+", "+manifestpath+")")
|
||||||
Cwtch.downloadFile(profile, handle, filepath, manifestpath, filekey)
|
Cwtch.downloadFile(profile, handle, filepath, manifestpath, filekey)
|
||||||
}
|
}
|
||||||
|
"CheckDownloadStatus" -> {
|
||||||
|
val profile = (a.get("ProfileOnion") as? String) ?: ""
|
||||||
|
val fileKey = (a.get("fileKey") as? String) ?: ""
|
||||||
|
Cwtch.checkDownloadStatus(profile, fileKey)
|
||||||
|
}
|
||||||
"SendProfileEvent" -> {
|
"SendProfileEvent" -> {
|
||||||
val onion = (a.get("onion") as? String) ?: ""
|
val onion = (a.get("onion") as? String) ?: ""
|
||||||
val jsonEvent = (a.get("jsonEvent") as? String) ?: ""
|
val jsonEvent = (a.get("jsonEvent") as? String) ?: ""
|
||||||
|
|
|
@ -46,6 +46,8 @@ abstract class Cwtch {
|
||||||
void DownloadFile(String profile, String handle, String filepath, String manifestpath, String filekey);
|
void DownloadFile(String profile, String handle, String filepath, String manifestpath, String filekey);
|
||||||
// ignore: non_constant_identifier_names
|
// ignore: non_constant_identifier_names
|
||||||
void CreateDownloadableFile(String profile, String handle, String filenameSuggestion, String filekey);
|
void CreateDownloadableFile(String profile, String handle, String filenameSuggestion, String filekey);
|
||||||
|
// ignore: non_constant_identifier_names
|
||||||
|
void CheckDownloadStatus(String profile, String fileKey);
|
||||||
|
|
||||||
// ignore: non_constant_identifier_names
|
// ignore: non_constant_identifier_names
|
||||||
void ArchiveConversation(String profile, String handle);
|
void ArchiveConversation(String profile, String handle);
|
||||||
|
|
|
@ -330,7 +330,7 @@ class CwtchNotifier {
|
||||||
profileCN.getProfile(data["ProfileOnion"])?.downloadUpdate(data["FileKey"], int.parse(data["Progress"]));
|
profileCN.getProfile(data["ProfileOnion"])?.downloadUpdate(data["FileKey"], int.parse(data["Progress"]));
|
||||||
break;
|
break;
|
||||||
case "FileDownloaded":
|
case "FileDownloaded":
|
||||||
profileCN.getProfile(data["ProfileOnion"])?.downloadMarkFinished(data["FileKey"]);
|
profileCN.getProfile(data["ProfileOnion"])?.downloadMarkFinished(data["FileKey"], data["FilePath"]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
EnvironmentConfig.debugLog("unhandled event: $type");
|
EnvironmentConfig.debugLog("unhandled event: $type");
|
||||||
|
|
|
@ -397,6 +397,19 @@ class CwtchFfi implements Cwtch {
|
||||||
// android only - do nothing
|
// android only - do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
// ignore: non_constant_identifier_names
|
||||||
|
void CheckDownloadStatus(String profileOnion, String fileKey) {
|
||||||
|
var checkDownloadStatus = library.lookup<NativeFunction<string_string_to_void_function>>("c_CheckDownloadStatus");
|
||||||
|
// ignore: non_constant_identifier_names
|
||||||
|
final CheckDownloadStatus = checkDownloadStatus.asFunction<VoidFromStringStringFn>();
|
||||||
|
final u1 = profileOnion.toNativeUtf8();
|
||||||
|
final u2 = fileKey.toNativeUtf8();
|
||||||
|
CheckDownloadStatus(u1, u1.length, u2, u2.length);
|
||||||
|
malloc.free(u1);
|
||||||
|
malloc.free(u2);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
// ignore: non_constant_identifier_names
|
// ignore: non_constant_identifier_names
|
||||||
void ResetTor() {
|
void ResetTor() {
|
||||||
|
|
|
@ -148,6 +148,12 @@ class CwtchGomobile implements Cwtch {
|
||||||
cwtchPlatform.invokeMethod("CreateDownloadableFile", {"ProfileOnion": profileOnion, "handle": contactHandle, "filename": filenameSuggestion, "filekey": filekey});
|
cwtchPlatform.invokeMethod("CreateDownloadableFile", {"ProfileOnion": profileOnion, "handle": contactHandle, "filename": filenameSuggestion, "filekey": filekey});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
// ignore: non_constant_identifier_names
|
||||||
|
void CheckDownloadStatus(String profileOnion, String fileKey) {
|
||||||
|
cwtchPlatform.invokeMethod("CheckDownloadStatus", {"ProfileOnion": profileOnion, "fileKey": fileKey});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
// ignore: non_constant_identifier_names
|
// ignore: non_constant_identifier_names
|
||||||
void ResetTor() {
|
void ResetTor() {
|
||||||
|
|
|
@ -381,14 +381,17 @@ class ProfileInfoState extends ChangeNotifier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void downloadMarkFinished(String fileKey) {
|
void downloadMarkFinished(String fileKey, String finalPath) {
|
||||||
if (!downloadActive(fileKey)) {
|
if (!downloadActive(fileKey)) {
|
||||||
print("error: received download completion notice for unknown download "+fileKey);
|
// happens as a result of a CheckDownloadStatus call,
|
||||||
} else {
|
// invoked from a historical (timeline) download message
|
||||||
this._downloads[fileKey]!.timeEnd = DateTime.now();
|
// so setting numChunks correctly shouldn't matter
|
||||||
this._downloads[fileKey]!.complete = true;
|
this.downloadInit(fileKey, 1);
|
||||||
notifyListeners();
|
|
||||||
}
|
}
|
||||||
|
this._downloads[fileKey]!.timeEnd = DateTime.now();
|
||||||
|
this._downloads[fileKey]!.downloadedTo = finalPath;
|
||||||
|
this._downloads[fileKey]!.complete = true;
|
||||||
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool downloadActive(String fileKey) {
|
bool downloadActive(String fileKey) {
|
||||||
|
@ -407,8 +410,12 @@ class ProfileInfoState extends ChangeNotifier {
|
||||||
return this._downloads.containsKey(fileKey) ? this._downloads[fileKey]!.progress() : 0.0;
|
return this._downloads.containsKey(fileKey) ? this._downloads[fileKey]!.progress() : 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String? downloadFinalPath(String fileKey) {
|
||||||
|
return this._downloads.containsKey(fileKey) ? this._downloads[fileKey]!.downloadedTo : null;
|
||||||
|
}
|
||||||
|
|
||||||
String downloadSpeed(String fileKey) {
|
String downloadSpeed(String fileKey) {
|
||||||
if (!downloadActive(fileKey)) {
|
if (!downloadActive(fileKey) || this._downloads[fileKey]!.chunksDownloaded == 0) {
|
||||||
return "0 B/s";
|
return "0 B/s";
|
||||||
}
|
}
|
||||||
var bytes = this._downloads[fileKey]!.chunksDownloaded * 4096;
|
var bytes = this._downloads[fileKey]!.chunksDownloaded * 4096;
|
||||||
|
@ -425,6 +432,7 @@ class FileDownloadProgress {
|
||||||
int chunksTotal = 1;
|
int chunksTotal = 1;
|
||||||
bool complete = false;
|
bool complete = false;
|
||||||
bool gotManifest = false;
|
bool gotManifest = false;
|
||||||
|
String? downloadedTo;
|
||||||
DateTime? timeStart;
|
DateTime? timeStart;
|
||||||
DateTime? timeEnd;
|
DateTime? timeEnd;
|
||||||
|
|
||||||
|
|
|
@ -35,38 +35,39 @@ Future<Message> messageHandler(BuildContext context, String profileOnion, String
|
||||||
try {
|
try {
|
||||||
var rawMessageEnvelopeFuture = Provider.of<FlwtchState>(context, listen: false).cwtch.GetMessage(profileOnion, contactHandle, index);
|
var rawMessageEnvelopeFuture = Provider.of<FlwtchState>(context, listen: false).cwtch.GetMessage(profileOnion, contactHandle, index);
|
||||||
return rawMessageEnvelopeFuture.then((dynamic rawMessageEnvelope) {
|
return rawMessageEnvelopeFuture.then((dynamic rawMessageEnvelope) {
|
||||||
dynamic messageWrapper = jsonDecode(rawMessageEnvelope);
|
var metadata = MessageMetadata(profileOnion, contactHandle, index, DateTime.now(), "", "", null, 0, false, true);
|
||||||
// There are 2 conditions in which this error condition can be met:
|
|
||||||
// 1. The application == nil, in which case this instance of the UI is already
|
|
||||||
// broken beyond repair, and will either be replaced by a new version, or requires a complete
|
|
||||||
// restart.
|
|
||||||
// 2. This index was incremented and we happened to fetch the timeline prior to the messages inclusion.
|
|
||||||
// This should be rare as Timeline addition/fetching is mutex protected and Dart itself will pipeline the
|
|
||||||
// calls to libCwtch-go - however because we use goroutines on the backend there is always a chance that one
|
|
||||||
// will find itself delayed.
|
|
||||||
// The second case is recoverable by tail-recursing this future.
|
|
||||||
if (messageWrapper['Message'] == null || messageWrapper['Message'] == '' || messageWrapper['Message'] == '{}') {
|
|
||||||
return Future.delayed(Duration(seconds: 2), () {
|
|
||||||
print("Tail recursive call to messageHandler called. This should be a rare event. If you see multiples of this log over a short period of time please log it as a bug.");
|
|
||||||
return messageHandler(context, profileOnion, contactHandle, index).then((value) => value);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct the initial metadata
|
|
||||||
var timestamp = DateTime.tryParse(messageWrapper['Timestamp'])!;
|
|
||||||
var senderHandle = messageWrapper['PeerID'];
|
|
||||||
var senderImage = messageWrapper['ContactImage'];
|
|
||||||
var flags = int.parse(messageWrapper['Flags'].toString(), radix: 2);
|
|
||||||
var ackd = messageWrapper['Acknowledged'];
|
|
||||||
var error = messageWrapper['Error'] != null;
|
|
||||||
String? signature;
|
|
||||||
// If this is a group, store the signature
|
|
||||||
if (contactHandle.length == GroupConversationHandleLength) {
|
|
||||||
signature = messageWrapper['Signature'];
|
|
||||||
}
|
|
||||||
var metadata = MessageMetadata(profileOnion, contactHandle, index, timestamp, senderHandle, senderImage, signature, flags, ackd, error);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
dynamic messageWrapper = jsonDecode(rawMessageEnvelope);
|
||||||
|
// There are 2 conditions in which this error condition can be met:
|
||||||
|
// 1. The application == nil, in which case this instance of the UI is already
|
||||||
|
// broken beyond repair, and will either be replaced by a new version, or requires a complete
|
||||||
|
// restart.
|
||||||
|
// 2. This index was incremented and we happened to fetch the timeline prior to the messages inclusion.
|
||||||
|
// This should be rare as Timeline addition/fetching is mutex protected and Dart itself will pipeline the
|
||||||
|
// calls to libCwtch-go - however because we use goroutines on the backend there is always a chance that one
|
||||||
|
// will find itself delayed.
|
||||||
|
// The second case is recoverable by tail-recursing this future.
|
||||||
|
if (messageWrapper['Message'] == null || messageWrapper['Message'] == '' || messageWrapper['Message'] == '{}') {
|
||||||
|
return Future.delayed(Duration(seconds: 2), () {
|
||||||
|
print("Tail recursive call to messageHandler called. This should be a rare event. If you see multiples of this log over a short period of time please log it as a bug.");
|
||||||
|
return messageHandler(context, profileOnion, contactHandle, index).then((value) => value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the initial metadata
|
||||||
|
var timestamp = DateTime.tryParse(messageWrapper['Timestamp'])!;
|
||||||
|
var senderHandle = messageWrapper['PeerID'];
|
||||||
|
var senderImage = messageWrapper['ContactImage'];
|
||||||
|
var flags = int.parse(messageWrapper['Flags'].toString());
|
||||||
|
var ackd = messageWrapper['Acknowledged'];
|
||||||
|
var error = messageWrapper['Error'] != null;
|
||||||
|
String? signature;
|
||||||
|
// If this is a group, store the signature
|
||||||
|
if (contactHandle.length == GroupConversationHandleLength) {
|
||||||
|
signature = messageWrapper['Signature'];
|
||||||
|
}
|
||||||
|
metadata = MessageMetadata(profileOnion, contactHandle, index, timestamp, senderHandle, senderImage, signature, flags, ackd, error);
|
||||||
|
|
||||||
dynamic message = jsonDecode(messageWrapper['Message']);
|
dynamic message = jsonDecode(messageWrapper['Message']);
|
||||||
var content = message['d'] as dynamic;
|
var content = message['d'] as dynamic;
|
||||||
var overlay = int.parse(message['o'].toString());
|
var overlay = int.parse(message['o'].toString());
|
||||||
|
@ -86,6 +87,7 @@ Future<Message> messageHandler(BuildContext context, String profileOnion, String
|
||||||
return MalformedMessage(metadata);
|
return MalformedMessage(metadata);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
print("an error! " + e.toString());
|
||||||
return MalformedMessage(metadata);
|
return MalformedMessage(metadata);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -39,7 +39,7 @@ class FileBubbleState extends State<FileBubble> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var fromMe = Provider.of<MessageMetadata>(context).senderHandle == Provider.of<ProfileInfoState>(context).onion;
|
var fromMe = Provider.of<MessageMetadata>(context).senderHandle == Provider.of<ProfileInfoState>(context).onion;
|
||||||
//isAccepted = Provider.of<ProfileInfoState>(context).contactList.getContact(widget.inviteTarget) != null;
|
var flagStarted = Provider.of<MessageMetadata>(context).flags & 0x02 > 0;
|
||||||
var borderRadiousEh = 15.0;
|
var borderRadiousEh = 15.0;
|
||||||
var showFileSharing = Provider.of<Settings>(context).isExperimentEnabled(FileSharingExperiment);
|
var showFileSharing = Provider.of<Settings>(context).isExperimentEnabled(FileSharingExperiment);
|
||||||
var prettyDate = DateFormat.yMd(Platform.localeName).add_jm().format(Provider.of<MessageMetadata>(context).timestamp);
|
var prettyDate = DateFormat.yMd(Platform.localeName).add_jm().format(Provider.of<MessageMetadata>(context).timestamp);
|
||||||
|
@ -66,27 +66,40 @@ class FileBubbleState extends State<FileBubble> {
|
||||||
? senderFileChrome(
|
? senderFileChrome(
|
||||||
AppLocalizations.of(context)!.messageFileSent, widget.nameSuggestion, widget.rootHash, widget.fileSize)
|
AppLocalizations.of(context)!.messageFileSent, widget.nameSuggestion, widget.rootHash, widget.fileSize)
|
||||||
: (fileChrome(AppLocalizations.of(context)!.messageFileOffered + ":", widget.nameSuggestion, widget.rootHash, widget.fileSize, Provider.of<ProfileInfoState>(context).downloadSpeed(widget.fileKey())));
|
: (fileChrome(AppLocalizations.of(context)!.messageFileOffered + ":", widget.nameSuggestion, widget.rootHash, widget.fileSize, Provider.of<ProfileInfoState>(context).downloadSpeed(widget.fileKey())));
|
||||||
|
|
||||||
Widget wdgDecorations;
|
Widget wdgDecorations;
|
||||||
if (!showFileSharing) {
|
if (!showFileSharing) {
|
||||||
wdgDecorations = Text('\u202F');
|
wdgDecorations = Text('\u202F');
|
||||||
} else if (fromMe) {
|
} else if (fromMe) {
|
||||||
wdgDecorations = MessageBubbleDecoration(ackd: Provider.of<MessageMetadata>(context).ackd, errored: Provider.of<MessageMetadata>(context).error, fromMe: fromMe, prettyDate: prettyDate);
|
wdgDecorations = MessageBubbleDecoration(ackd: Provider.of<MessageMetadata>(context).ackd, errored: Provider.of<MessageMetadata>(context).error, fromMe: fromMe, prettyDate: prettyDate);
|
||||||
} else if (Provider.of<ProfileInfoState>(context).downloadComplete(widget.fileKey())) {
|
} else if (Provider.of<ProfileInfoState>(context).downloadComplete(widget.fileKey())) {
|
||||||
wdgDecorations = Center(
|
// in this case, whatever marked download.complete would have also set the path
|
||||||
widthFactor: 1,
|
var path = Provider.of<ProfileInfoState>(context).downloadFinalPath(widget.fileKey())!;
|
||||||
child: Wrap(children: [
|
wdgDecorations = Text('Saved to: ' + path + '\u202F');
|
||||||
Padding(padding: EdgeInsets.all(5), child: ElevatedButton(child: Text(AppLocalizations.of(context)!.openFolderButton + '\u202F'), onPressed: _btnAccept)),
|
|
||||||
]));
|
|
||||||
} else if (Provider.of<ProfileInfoState>(context).downloadActive(widget.fileKey())) {
|
} else if (Provider.of<ProfileInfoState>(context).downloadActive(widget.fileKey())) {
|
||||||
if (!Provider.of<ProfileInfoState>(context).downloadGotManifest(widget.fileKey())) {
|
if (!Provider.of<ProfileInfoState>(context).downloadGotManifest(
|
||||||
wdgDecorations = Text(AppLocalizations.of(context)!.retrievingManifestMessage + '\u202F');
|
widget.fileKey())) {
|
||||||
|
wdgDecorations = Text(
|
||||||
|
AppLocalizations.of(context)!.retrievingManifestMessage + '\u202F');
|
||||||
} else {
|
} else {
|
||||||
wdgDecorations = LinearProgressIndicator(
|
wdgDecorations = LinearProgressIndicator(
|
||||||
value: Provider.of<ProfileInfoState>(context).downloadProgress(widget.fileKey()),
|
value: Provider.of<ProfileInfoState>(context).downloadProgress(
|
||||||
color: Provider.of<Settings>(context).theme.defaultButtonActiveColor(),
|
widget.fileKey()),
|
||||||
|
color: Provider
|
||||||
|
.of<Settings>(context)
|
||||||
|
.theme
|
||||||
|
.defaultButtonActiveColor(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
} else if (flagStarted) {
|
||||||
|
// in this case, the download was done in a previous application launch,
|
||||||
|
// so we probably have to request an info lookup
|
||||||
|
var path = Provider.of<ProfileInfoState>(context).downloadFinalPath(widget.fileKey());
|
||||||
|
if (path == null) {
|
||||||
|
wdgDecorations = Text('Checking download status...' + '\u202F');
|
||||||
|
Provider.of<FlwtchState>(context, listen: false).cwtch.CheckDownloadStatus(Provider.of<ProfileInfoState>(context, listen: false).onion, widget.fileKey());
|
||||||
|
} else {
|
||||||
|
wdgDecorations = Text('Saved to: ' + (path??"null") + '\u202F');
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
wdgDecorations = Center(
|
wdgDecorations = Center(
|
||||||
widthFactor: 1,
|
widthFactor: 1,
|
||||||
|
@ -135,10 +148,13 @@ class FileBubbleState extends State<FileBubble> {
|
||||||
File? file;
|
File? file;
|
||||||
var profileOnion = Provider.of<ProfileInfoState>(context, listen: false).onion;
|
var profileOnion = Provider.of<ProfileInfoState>(context, listen: false).onion;
|
||||||
var handle = Provider.of<MessageMetadata>(context, listen: false).senderHandle;
|
var handle = Provider.of<MessageMetadata>(context, listen: false).senderHandle;
|
||||||
|
var contact = Provider.of<ContactInfoState>(context, listen: false).onion;
|
||||||
|
var idx = Provider.of<MessageMetadata>(context, listen: false).messageIndex;
|
||||||
|
|
||||||
if (Platform.isAndroid) {
|
if (Platform.isAndroid) {
|
||||||
//todo: would be better to only call downloadInit if CreateDownloadableFile results in a user-pick (they might cancel)
|
|
||||||
Provider.of<ProfileInfoState>(context, listen: false).downloadInit(widget.fileKey(), (widget.fileSize / 4096).ceil());
|
Provider.of<ProfileInfoState>(context, listen: false).downloadInit(widget.fileKey(), (widget.fileSize / 4096).ceil());
|
||||||
|
Provider.of<FlwtchState>(context, listen: false).cwtch.UpdateMessageFlags(profileOnion, contact, idx, Provider.of<MessageMetadata>(context, listen: false).flags | 0x02);
|
||||||
|
Provider.of<MessageMetadata>(context, listen: false).flags |= 0x02;
|
||||||
Provider.of<FlwtchState>(context, listen: false).cwtch.CreateDownloadableFile(profileOnion, handle, widget.nameSuggestion, widget.fileKey());
|
Provider.of<FlwtchState>(context, listen: false).cwtch.CreateDownloadableFile(profileOnion, handle, widget.nameSuggestion, widget.fileKey());
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
|
@ -148,6 +164,8 @@ class FileBubbleState extends State<FileBubble> {
|
||||||
print("saving to " + file.path);
|
print("saving to " + file.path);
|
||||||
var manifestPath = file.path + ".manifest";
|
var manifestPath = file.path + ".manifest";
|
||||||
Provider.of<ProfileInfoState>(context, listen: false).downloadInit(widget.fileKey(), (widget.fileSize / 4096).ceil());
|
Provider.of<ProfileInfoState>(context, listen: false).downloadInit(widget.fileKey(), (widget.fileSize / 4096).ceil());
|
||||||
|
Provider.of<FlwtchState>(context, listen: false).cwtch.UpdateMessageFlags(profileOnion, contact, idx, Provider.of<MessageMetadata>(context, listen: false).flags | 0x02);
|
||||||
|
Provider.of<MessageMetadata>(context, listen: false).flags |= 0x02;
|
||||||
Provider.of<FlwtchState>(context, listen: false).cwtch.DownloadFile(profileOnion, handle, file.path, manifestPath, widget.fileKey());
|
Provider.of<FlwtchState>(context, listen: false).cwtch.DownloadFile(profileOnion, handle, file.path, manifestPath, widget.fileKey());
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -131,7 +131,7 @@ class InvitationBubbleState extends State<InvitationBubble> {
|
||||||
var contact = Provider.of<ContactInfoState>(context, listen: false).onion;
|
var contact = Provider.of<ContactInfoState>(context, listen: false).onion;
|
||||||
var idx = Provider.of<MessageMetadata>(context, listen: false).messageIndex;
|
var idx = Provider.of<MessageMetadata>(context, listen: false).messageIndex;
|
||||||
Provider.of<FlwtchState>(context, listen: false).cwtch.UpdateMessageFlags(profileOnion, contact, idx, Provider.of<MessageMetadata>(context, listen: false).flags | 0x01);
|
Provider.of<FlwtchState>(context, listen: false).cwtch.UpdateMessageFlags(profileOnion, contact, idx, Provider.of<MessageMetadata>(context, listen: false).flags | 0x01);
|
||||||
Provider.of<MessageMetadata>(context).flags |= 0x01;
|
Provider.of<MessageMetadata>(context, listen: false).flags |= 0x01;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ class _MessageListState extends State<MessageList> {
|
||||||
// Already includes MessageRow,,
|
// Already includes MessageRow,,
|
||||||
return message.getWidget(context);
|
return message.getWidget(context);
|
||||||
} else {
|
} else {
|
||||||
return MessageLoadingBubble();
|
return Text('');//MessageLoadingBubble();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue