Fixing Duplicate Key Issues + FileBubble SetState Builder Issues

This commit is contained in:
Sarah Jamie Lewis 2021-12-15 13:43:14 -08:00
parent 51fae2e7ef
commit a4cb5051b5
15 changed files with 331 additions and 348 deletions

View File

@ -282,8 +282,6 @@ class ProfileInfoState extends ChangeNotifier {
this._contacts.updateLastMessageTime(this._contacts._contacts.first.identifier, this._contacts._contacts.first.lastMessageTime);
}
}
}
// Parse out the server list json into our server info state struct...

View File

@ -58,12 +58,16 @@ Message compileOverlay(MessageMetadata metadata, String messageData) {
}
Future<Message> messageHandler(BuildContext context, String profileOnion, int conversationIdentifier, int index, {bool byID = false}) {
var cache = Provider.of<ProfileInfoState>(context).contactList.getContact(conversationIdentifier)?.messageCache;
try {
var cache = Provider.of<ProfileInfoState>(context, listen: false).contactList.getContact(conversationIdentifier)?.messageCache;
if (cache != null && cache.length > index) {
if (cache[index] != null) {
return Future.value(compileOverlay(cache[index]!.metadata, cache[index]!.wrapper));
}
}
} catch (e) {
// provider check failed...make an expensive call...
}
try {
Future<dynamic> rawMessageEnvelopeFuture;

View File

@ -19,7 +19,6 @@ class FileMessage extends Message {
@override
Widget getWidget(BuildContext context, Key key) {
return ChangeNotifierProvider.value(
key: key,
value: this.metadata,
builder: (bcontext, child) {
dynamic shareObj = jsonDecode(this.content);

View File

@ -19,7 +19,6 @@ class InviteMessage extends Message {
@override
Widget getWidget(BuildContext context, Key key) {
return ChangeNotifierProvider.value(
key: key,
value: this.metadata,
builder: (bcontext, child) {
String inviteTarget;
@ -37,7 +36,7 @@ class InviteMessage extends Message {
inviteTarget = jsonObj['GroupID'];
inviteNick = jsonObj['GroupName'];
} else {
return MessageRow(MalformedBubble(), key: key);
return MessageRow(MalformedBubble());
}
}
return MessageRow(InvitationBubble(overlay, inviteTarget, inviteNick, invite), key: key);

View File

@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:cwtch/models/message.dart';
import 'package:cwtch/models/messages/malformedmessage.dart';
import 'package:cwtch/widgets/malformedbubble.dart';
import 'package:cwtch/widgets/messagerow.dart';
import 'package:cwtch/widgets/quotedmessage.dart';
import 'package:flutter/widgets.dart';
@ -51,7 +52,7 @@ class QuotedMessage extends Message {
dynamic message = jsonDecode(this.content);
return Text(message["body"]);
} catch (e) {
return MalformedMessage(this.metadata).getWidget(context, Key("malformed"));
return MalformedBubble();
}
});
}
@ -67,7 +68,7 @@ class QuotedMessage extends Message {
dynamic message = jsonDecode(this.content);
if (message["body"] == null || message["quotedHash"] == null) {
return MalformedMessage(this.metadata).getWidget(context, key);
return MalformedBubble();
}
var quotedMessagePotentials = Provider.of<FlwtchState>(context).cwtch.GetMessageByContentHash(metadata.profileOnion, metadata.conversationIdentifier, message["quotedHash"]);
@ -94,14 +95,14 @@ class QuotedMessage extends Message {
return MessageRow(
QuotedMessageBubble(message["body"], quotedMessage.then((LocallyIndexedMessage? localIndex) {
if (localIndex != null) {
return messageHandler(context, metadata.profileOnion, metadata.conversationIdentifier, localIndex.index);
return messageHandler(bcontext, metadata.profileOnion, metadata.conversationIdentifier, localIndex.index);
}
return MalformedMessage(this.metadata);
})),
key: key);
});
} catch (e) {
return MalformedMessage(this.metadata).getWidget(context, key);
return MalformedBubble();
}
}
}

View File

@ -229,7 +229,7 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
),
Visibility(
visible: settings.isExperimentEnabled(FileSharingExperiment),
child: Column(children:[
child: Column(children: [
SwitchListTile(
title: Text(AppLocalizations.of(context)!.settingImagePreviews, style: TextStyle(color: settings.current().mainTextColor())),
subtitle: Text(AppLocalizations.of(context)!.settingImagePreviewsDescription),

View File

@ -10,14 +10,12 @@ import '../main.dart';
import '../model.dart';
import '../settings.dart';
class ProfileServersView extends StatefulWidget {
@override
_ProfileServersView createState() => _ProfileServersView();
}
class _ProfileServersView extends State<ProfileServersView> {
@override
void dispose() {
super.dispose();
@ -25,9 +23,10 @@ class _ProfileServersView extends State<ProfileServersView> {
@override
Widget build(BuildContext context) {
var knownServers = Provider.of<ProfileInfoState>(context).serverList.servers.map<String>((RemoteServerInfoState remoteServer) { return remoteServer.onion + ".onion"; }).toSet();
var importServerList = Provider.of<ServerListState>(context).servers.where((server) => !knownServers.contains(server.onion) ).map<DropdownMenuItem<String>>((ServerInfoState serverInfo) {
var knownServers = Provider.of<ProfileInfoState>(context).serverList.servers.map<String>((RemoteServerInfoState remoteServer) {
return remoteServer.onion + ".onion";
}).toSet();
var importServerList = Provider.of<ServerListState>(context).servers.where((server) => !knownServers.contains(server.onion)).map<DropdownMenuItem<String>>((ServerInfoState serverInfo) {
return DropdownMenuItem<String>(
value: serverInfo.onion,
child: Text(
@ -37,20 +36,17 @@ class _ProfileServersView extends State<ProfileServersView> {
);
}).toList();
importServerList.insert(0, DropdownMenuItem<String>(
value: "",
child: Text(AppLocalizations.of(context)!.importLocalServerSelectText)));
importServerList.insert(0, DropdownMenuItem<String>(value: "", child: Text(AppLocalizations.of(context)!.importLocalServerSelectText)));
return Scaffold(
appBar: AppBar(
title: Text(MediaQuery
.of(context)
.size
.width > 600 ? AppLocalizations.of(context)!.manageKnownServersLong : AppLocalizations.of(context)!.manageKnownServersShort),
title: Text(MediaQuery.of(context).size.width > 600 ? AppLocalizations.of(context)!.manageKnownServersLong : AppLocalizations.of(context)!.manageKnownServersShort),
),
body: Consumer<ProfileInfoState>(builder: (context, profile, child) {
body: Consumer<ProfileInfoState>(
builder: (context, profile, child) {
ProfileServerListState servers = profile.serverList;
final tiles = servers.servers.map((RemoteServerInfoState server) {
final tiles = servers.servers.map(
(RemoteServerInfoState server) {
return ChangeNotifierProvider<RemoteServerInfoState>.value(
value: server,
builder: (context, child) => RepaintBoundary(child: RemoteServerRow()),
@ -63,20 +59,19 @@ class _ProfileServersView extends State<ProfileServersView> {
tiles: tiles,
).toList();
final importCard = Card( child: ListTile(
final importCard = Card(
child: ListTile(
title: Text(AppLocalizations.of(context)!.importLocalServerLabel),
leading: Icon(CwtchIcons.add_circle_24px , color: Provider.of<Settings>(context).current().mainTextColor()),
leading: Icon(CwtchIcons.add_circle_24px, color: Provider.of<Settings>(context).current().mainTextColor()),
trailing: DropdownButton(
onChanged: (String? importServer) {
if (importServer!.isNotEmpty) {
var server = Provider.of<ServerListState>(context).getServer(importServer)!;
showImportConfirm(context, profile.onion, server.onion, server.description, server.serverBundle);
}
},
value: "",
items: importServerList,
)));
return LayoutBuilder(builder: (BuildContext context, BoxConstraints viewportConstraints) {
@ -84,16 +79,11 @@ class _ProfileServersView extends State<ProfileServersView> {
isAlwaysShown: true,
child: SingleChildScrollView(
clipBehavior: Clip.antiAlias,
child:
Container(
child: Container(
margin: EdgeInsets.fromLTRB(5, 0, 5, 10),
padding: EdgeInsets.fromLTRB(5, 0, 5, 10),
child: Column(children: [
if (importServerList.length > 1) importCard,
Column( children: divided )
]))));});
child: Column(children: [if (importServerList.length > 1) importCard, Column(children: divided)]))));
});
return ListView(children: divided);
},
@ -102,7 +92,7 @@ class _ProfileServersView extends State<ProfileServersView> {
showImportConfirm(BuildContext context, String profileHandle, String serverHandle, String serverDesc, String bundle) {
var serverLabel = serverDesc.isNotEmpty ? serverDesc : serverHandle;
serverHandle = serverHandle.substring(0, serverHandle.length-6 ); // remove '.onion'
serverHandle = serverHandle.substring(0, serverHandle.length - 6); // remove '.onion'
// set up the buttons
Widget cancelButton = ElevatedButton(
child: Text(AppLocalizations.of(context)!.cancel),
@ -118,15 +108,9 @@ class _ProfileServersView extends State<ProfileServersView> {
Future.delayed(const Duration(milliseconds: 500), () {
var profile = Provider.of<ProfileInfoState>(context);
if (profile.serverList.getServer(serverHandle) != null) {
profile.serverList.getServer(serverHandle)?.updateDescription(
serverDesc);
profile.serverList.getServer(serverHandle)?.updateDescription(serverDesc);
Provider
.of<FlwtchState>(context, listen: false)
.cwtch
.SetConversationAttribute(profile.onion, profile.serverList
.getServer(serverHandle)
!.identifier, "server.description", serverDesc);
Provider.of<FlwtchState>(context, listen: false).cwtch.SetConversationAttribute(profile.onion, profile.serverList.getServer(serverHandle)!.identifier, "server.description", serverDesc);
}
});
Navigator.of(context).pop();
@ -149,7 +133,4 @@ class _ProfileServersView extends State<ProfileServersView> {
},
);
}
}

View File

@ -50,9 +50,7 @@ class _RemoteServerViewState extends State<RemoteServerView> {
Widget build(BuildContext context) {
return Consumer3<ProfileInfoState, RemoteServerInfoState, Settings>(builder: (context, profile, serverInfoState, settings, child) {
return Scaffold(
appBar: AppBar(
title: Text(ctrlrDesc.text.isNotEmpty ? ctrlrDesc.text : serverInfoState.onion)
),
appBar: AppBar(title: Text(ctrlrDesc.text.isNotEmpty ? ctrlrDesc.text : serverInfoState.onion)),
body: Container(
margin: EdgeInsets.fromLTRB(30, 0, 30, 10),
padding: EdgeInsets.fromLTRB(20, 0, 20, 10),
@ -64,9 +62,7 @@ class _RemoteServerViewState extends State<RemoteServerView> {
SizedBox(
height: 20,
),
SelectableText(
serverInfoState.onion
),
SelectableText(serverInfoState.onion),
// Description
SizedBox(
@ -93,15 +89,18 @@ class _RemoteServerViewState extends State<RemoteServerView> {
height: 20,
),
Padding(padding: EdgeInsets.all(8), child: Text( AppLocalizations.of(context)!.groupsOnThisServerLabel),),
Padding(
padding: EdgeInsets.all(8),
child: Text(AppLocalizations.of(context)!.groupsOnThisServerLabel),
),
Expanded(child: _buildGroupsList(serverInfoState))
])));
});
}
Widget _buildGroupsList(RemoteServerInfoState serverInfoState) {
final tiles = serverInfoState.groups.map((ContactInfoState group) {
final tiles = serverInfoState.groups.map(
(ContactInfoState group) {
return ChangeNotifierProvider<ContactInfoState>.value(
value: group,
builder: (context, child) => RepaintBoundary(child: _buildGroupRow(group)), // ServerRow()),
@ -126,8 +125,7 @@ class _RemoteServerViewState extends State<RemoteServerView> {
Widget _buildGroupRow(ContactInfoState group) {
return Padding(
padding: const EdgeInsets.all(6.0), //border size
child: Column(
children: [
child: Column(children: [
Text(
group.nickname,
style: Provider.of<FlwtchState>(context).biggerFont.apply(color: Provider.of<Settings>(context).theme.portraitOnlineBorderColor()),
@ -143,9 +141,6 @@ class _RemoteServerViewState extends State<RemoteServerView> {
overflow: TextOverflow.ellipsis,
style: TextStyle(color: Provider.of<Settings>(context).theme.portraitOnlineBorderColor()),
)))
])
);
]));
}
}

View File

@ -49,6 +49,26 @@ class FileBubbleState extends State<FileBubble> {
var borderRadiousEh = 15.0;
var showFileSharing = Provider.of<Settings>(context).isExperimentEnabled(FileSharingExperiment);
var prettyDate = DateFormat.yMd(Platform.localeName).add_jm().format(Provider.of<MessageMetadata>(context).timestamp);
var downloadComplete = Provider.of<ProfileInfoState>(context).downloadComplete(widget.fileKey());
var downloadInterrupted = Provider.of<ProfileInfoState>(context).downloadInterrupted(widget.fileKey());
if (downloadInterrupted) {
Provider.of<FlwtchState>(context, listen: false).cwtch.CheckDownloadStatus(Provider.of<ProfileInfoState>(context, listen: false).onion, widget.fileKey());
}
var path = Provider.of<ProfileInfoState>(context).downloadFinalPath(widget.fileKey());
if (downloadComplete) {
var lpath = path!.toLowerCase();
if (lpath.endsWith("jpg") || lpath.endsWith("jpeg") || lpath.endsWith("png") || lpath.endsWith("gif") || lpath.endsWith("webp") || lpath.endsWith("bmp")) {
if (myFile == null) {
setState(() {
myFile = new File(path);
});
}
}
}
var downloadActive = Provider.of<ProfileInfoState>(context).downloadActive(widget.fileKey());
var downloadGotManifest = Provider.of<ProfileInfoState>(context).downloadGotManifest(widget.fileKey());
// If the sender is not us, then we want to give them a nickname...
var senderDisplayStr = "";
@ -78,17 +98,10 @@ class FileBubbleState extends State<FileBubble> {
wdgDecorations = Text('\u202F');
} else if (fromMe) {
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 (downloadComplete) {
// in this case, whatever marked download.complete would have also set the path
var path = Provider.of<ProfileInfoState>(context).downloadFinalPath(widget.fileKey())!;
var lpath = path.toLowerCase();
var lpath = path!.toLowerCase();
if (lpath.endsWith("jpg") || lpath.endsWith("jpeg") || lpath.endsWith("png") || lpath.endsWith("gif") || lpath.endsWith("webp") || lpath.endsWith("bmp")) {
if (myFile == null) {
setState(() {
myFile = new File(path);
});
}
isPreview = true;
wdgDecorations = GestureDetector(
child: Image.file(
@ -110,8 +123,8 @@ class FileBubbleState extends State<FileBubble> {
} else {
wdgDecorations = Text(AppLocalizations.of(context)!.fileSavedTo + ': ' + path + '\u202F');
}
} else if (Provider.of<ProfileInfoState>(context).downloadActive(widget.fileKey())) {
if (!Provider.of<ProfileInfoState>(context).downloadGotManifest(widget.fileKey())) {
} else if (downloadActive) {
if (!downloadGotManifest) {
wdgDecorations = Text(AppLocalizations.of(context)!.retrievingManifestMessage + '\u202F');
} else {
wdgDecorations = LinearProgressIndicator(
@ -122,9 +135,8 @@ class FileBubbleState extends State<FileBubble> {
} else if (flagStarted) {
// in this case, the download was done in a previous application launch,
// so we probably have to request an info lookup
if (!Provider.of<ProfileInfoState>(context).downloadInterrupted(widget.fileKey())) {
if (!downloadInterrupted) {
wdgDecorations = Text(AppLocalizations.of(context)!.fileCheckingStatus + '...' + '\u202F');
Provider.of<FlwtchState>(context, listen: false).cwtch.CheckDownloadStatus(Provider.of<ProfileInfoState>(context, listen: false).onion, widget.fileKey());
} else {
var path = Provider.of<ProfileInfoState>(context).downloadFinalPath(widget.fileKey()) ?? "";
wdgDecorations = Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
@ -140,7 +152,6 @@ class FileBubbleState extends State<FileBubble> {
]));
}
return Container(
constraints: constraints,
decoration: BoxDecoration(
@ -193,7 +204,7 @@ class FileBubbleState extends State<FileBubble> {
Provider.of<ProfileInfoState>(context, listen: false).downloadInit(widget.fileKey(), (widget.fileSize / 4096).ceil());
Provider.of<FlwtchState>(context, listen: false).cwtch.SetMessageAttribute(profileOnion, conversation, 0, idx, "file-downloaded", "true");
//Provider.of<MessageMetadata>(context, listen: false).flags |= 0x02;
ContactInfoState? contact = Provider.of<ProfileInfoState>(context).contactList.findContact(Provider.of<MessageMetadata>(context).senderHandle);
ContactInfoState? contact = Provider.of<ProfileInfoState>(context, listen: false).contactList.findContact(Provider.of<MessageMetadata>(context).senderHandle);
if (contact != null) {
Provider.of<FlwtchState>(context, listen: false).cwtch.DownloadFile(profileOnion, contact.identifier, file.path, manifestPath, widget.fileKey());
}

View File

@ -60,7 +60,7 @@ class _CwtchFolderPickerState extends State<CwtchFolderPicker> {
}
},
icon: Icon(Icons.folder),
tooltip: "Browse",//todo: l18n
tooltip: "Browse", //todo: l18n
)
]));
}

View File

@ -25,28 +25,25 @@ class _RemoteServerRowState extends State<RemoteServerRow> {
var server = Provider.of<RemoteServerInfoState>(context);
var description = server.description.isNotEmpty ? server.description : server.onion;
var running = server.status == "Synced";
return Consumer<ProfileInfoState>(
builder: (context, profile, child) {
return Card(clipBehavior: Clip.antiAlias,
return Consumer<ProfileInfoState>(builder: (context, profile, child) {
return Card(
clipBehavior: Clip.antiAlias,
margin: EdgeInsets.all(0.0),
child: InkWell(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Padding(
padding: const EdgeInsets.all(6.0), //border size
child: Icon(CwtchIcons.dns_24px,
color: running ? Provider.of<Settings>(context).theme.portraitOnlineBorderColor() : Provider.of<Settings>(context).theme.portraitOfflineBorderColor(),
size: 64)
),
color: running ? Provider.of<Settings>(context).theme.portraitOnlineBorderColor() : Provider.of<Settings>(context).theme.portraitOfflineBorderColor(), size: 64)),
Expanded(
child: Column(
children: [
Text(
description,
semanticsLabel: description,
style: Provider.of<FlwtchState>(context).biggerFont.apply(color: running ? Provider.of<Settings>(context).theme.portraitOnlineBorderColor() : Provider.of<Settings>(context).theme.portraitOfflineBorderColor()),
style: Provider.of<FlwtchState>(context)
.biggerFont
.apply(color: running ? Provider.of<Settings>(context).theme.portraitOnlineBorderColor() : Provider.of<Settings>(context).theme.portraitOfflineBorderColor()),
softWrap: true,
overflow: TextOverflow.ellipsis,
),
@ -61,7 +58,6 @@ class _RemoteServerRowState extends State<RemoteServerRow> {
)))
],
)),
]),
onTap: () {
Navigator.of(context).push(MaterialPageRoute<void>(
@ -72,7 +68,7 @@ class _RemoteServerRowState extends State<RemoteServerRow> {
child: RemoteServerView(),
);
}));
}
));});
}));
});
}
}

View File

@ -76,8 +76,7 @@ class _ServerRowState extends State<ServerRow> {
]),
onTap: () {
_pushEditServer(server);
}
));
}));
}
void _pushEditServer(ServerInfoState server) {