diff --git a/lib/model.dart b/lib/model.dart index ae0ba25a..c72a45d2 100644 --- a/lib/model.dart +++ b/lib/model.dart @@ -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... diff --git a/lib/models/message.dart b/lib/models/message.dart index 4df9eace..6fb1028b 100644 --- a/lib/models/message.dart +++ b/lib/models/message.dart @@ -58,11 +58,15 @@ Message compileOverlay(MessageMetadata metadata, String messageData) { } Future messageHandler(BuildContext context, String profileOnion, int conversationIdentifier, int index, {bool byID = false}) { - var cache = Provider.of(context).contactList.getContact(conversationIdentifier)?.messageCache; - if (cache != null && cache.length > index) { - if (cache[index] != null) { - return Future.value(compileOverlay(cache[index]!.metadata, cache[index]!.wrapper)); + try { + var cache = Provider.of(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 { diff --git a/lib/models/messages/filemessage.dart b/lib/models/messages/filemessage.dart index 9254c6d2..a0eba982 100644 --- a/lib/models/messages/filemessage.dart +++ b/lib/models/messages/filemessage.dart @@ -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); diff --git a/lib/models/messages/invitemessage.dart b/lib/models/messages/invitemessage.dart index 149ba5e0..2965abc9 100644 --- a/lib/models/messages/invitemessage.dart +++ b/lib/models/messages/invitemessage.dart @@ -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); diff --git a/lib/models/messages/quotedmessage.dart b/lib/models/messages/quotedmessage.dart index 5a69ca91..2eb54b28 100644 --- a/lib/models/messages/quotedmessage.dart +++ b/lib/models/messages/quotedmessage.dart @@ -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(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(); } } } diff --git a/lib/models/profileservers.dart b/lib/models/profileservers.dart index 5f422538..4b868b95 100644 --- a/lib/models/profileservers.dart +++ b/lib/models/profileservers.dart @@ -35,7 +35,7 @@ class ProfileServerListState extends ChangeNotifier { // online v offline if (a.status == "Synced" && b.status != "Synced") { return -1; - } else if (a.status != "Synced" && b.status == "Synced") { + } else if (a.status != "Synced" && b.status == "Synced") { return 1; } @@ -73,7 +73,7 @@ class RemoteServerInfoState extends ChangeNotifier { List _groups = []; RemoteServerInfoState({required this.onion, required this.identifier, required this.description, required this.status}); - + void updateDescription(String newDescription) { this.description = newDescription; notifyListeners(); diff --git a/lib/views/addeditprofileview.dart b/lib/views/addeditprofileview.dart index 03084ca2..8065c9b4 100644 --- a/lib/views/addeditprofileview.dart +++ b/lib/views/addeditprofileview.dart @@ -107,7 +107,7 @@ class _AddEditProfileViewState extends State { labelText: AppLocalizations.of(context)!.yourDisplayName, validator: (value) { if (value.isEmpty) { - return AppLocalizations.of(context)!.displayNameTooltip; + return AppLocalizations.of(context)!.displayNameTooltip; } return null; }, diff --git a/lib/views/contactsview.dart b/lib/views/contactsview.dart index a05ef4df..5c2f564d 100644 --- a/lib/views/contactsview.dart +++ b/lib/views/contactsview.dart @@ -117,7 +117,7 @@ class _ContactsViewState extends State { if (Provider.of(context, listen: false).isExperimentEnabled(ServerManagementExperiment)) { actions.add(IconButton( icon: Icon(CwtchIcons.dns_24px), - tooltip: AppLocalizations.of(context)!.manageKnownServersButton, + tooltip: AppLocalizations.of(context)!.manageKnownServersButton, onPressed: () { _pushServers(); })); diff --git a/lib/views/globalsettingsview.dart b/lib/views/globalsettingsview.dart index 89f6f865..5b4d5d64 100644 --- a/lib/views/globalsettingsview.dart +++ b/lib/views/globalsettingsview.dart @@ -229,7 +229,7 @@ class _GlobalSettingsViewState extends State { ), 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), diff --git a/lib/views/profileserversview.dart b/lib/views/profileserversview.dart index 7ac06520..bd4fd40e 100644 --- a/lib/views/profileserversview.dart +++ b/lib/views/profileserversview.dart @@ -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 { - @override void dispose() { super.dispose(); @@ -25,9 +23,10 @@ class _ProfileServersView extends State { @override Widget build(BuildContext context) { - - var knownServers = Provider.of(context).serverList.servers.map((RemoteServerInfoState remoteServer) { return remoteServer.onion + ".onion"; }).toSet(); - var importServerList = Provider.of(context).servers.where((server) => !knownServers.contains(server.onion) ).map>((ServerInfoState serverInfo) { + var knownServers = Provider.of(context).serverList.servers.map((RemoteServerInfoState remoteServer) { + return remoteServer.onion + ".onion"; + }).toSet(); + var importServerList = Provider.of(context).servers.where((server) => !knownServers.contains(server.onion)).map>((ServerInfoState serverInfo) { return DropdownMenuItem( value: serverInfo.onion, child: Text( @@ -37,25 +36,22 @@ class _ProfileServersView extends State { ); }).toList(); - importServerList.insert(0, DropdownMenuItem( - value: "", - child: Text(AppLocalizations.of(context)!.importLocalServerSelectText))); + importServerList.insert(0, DropdownMenuItem(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(builder: (context, profile, child) { + body: Consumer( + builder: (context, profile, child) { ProfileServerListState servers = profile.serverList; - final tiles = servers.servers.map((RemoteServerInfoState server) { - return ChangeNotifierProvider.value( - value: server, - builder: (context, child) => RepaintBoundary(child: RemoteServerRow()), - ); - }, + final tiles = servers.servers.map( + (RemoteServerInfoState server) { + return ChangeNotifierProvider.value( + value: server, + builder: (context, child) => RepaintBoundary(child: RemoteServerRow()), + ); + }, ); final divided = ListTile.divideTiles( @@ -63,37 +59,31 @@ class _ProfileServersView extends State { tiles: tiles, ).toList(); - final importCard = Card( child: ListTile( - title: Text(AppLocalizations.of(context)!.importLocalServerLabel), - leading: Icon(CwtchIcons.add_circle_24px , color: Provider.of(context).current().mainTextColor()), - trailing: DropdownButton( - onChanged: (String? importServer) { - if (importServer!.isNotEmpty) { - var server = Provider.of(context).getServer(importServer)!; - showImportConfirm(context, profile.onion, server.onion, server.description, server.serverBundle); - } - - }, - value: "", - items: importServerList, - - ))); + final importCard = Card( + child: ListTile( + title: Text(AppLocalizations.of(context)!.importLocalServerLabel), + leading: Icon(CwtchIcons.add_circle_24px, color: Provider.of(context).current().mainTextColor()), + trailing: DropdownButton( + onChanged: (String? importServer) { + if (importServer!.isNotEmpty) { + var server = Provider.of(context).getServer(importServer)!; + showImportConfirm(context, profile.onion, server.onion, server.description, server.serverBundle); + } + }, + value: "", + items: importServerList, + ))); return LayoutBuilder(builder: (BuildContext context, BoxConstraints viewportConstraints) { - return Scrollbar( - isAlwaysShown: true, - child: SingleChildScrollView( - clipBehavior: Clip.antiAlias, - 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 ) - ]))));}); + return Scrollbar( + isAlwaysShown: true, + child: SingleChildScrollView( + clipBehavior: Clip.antiAlias, + 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)])))); + }); return ListView(children: divided); }, @@ -102,7 +92,7 @@ class _ProfileServersView extends State { 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 { Future.delayed(const Duration(milliseconds: 500), () { var profile = Provider.of(context); if (profile.serverList.getServer(serverHandle) != null) { - profile.serverList.getServer(serverHandle)?.updateDescription( - serverDesc); + profile.serverList.getServer(serverHandle)?.updateDescription(serverDesc); - Provider - .of(context, listen: false) - .cwtch - .SetConversationAttribute(profile.onion, profile.serverList - .getServer(serverHandle) - !.identifier, "server.description", serverDesc); + Provider.of(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 { }, ); } - - - -} \ No newline at end of file +} diff --git a/lib/views/remoteserverview.dart b/lib/views/remoteserverview.dart index bc940807..e43a79e5 100644 --- a/lib/views/remoteserverview.dart +++ b/lib/views/remoteserverview.dart @@ -50,63 +50,62 @@ class _RemoteServerViewState extends State { Widget build(BuildContext context) { return Consumer3(builder: (context, profile, serverInfoState, settings, child) { return Scaffold( - 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), - child: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ - SizedBox( - height: 20, - ), - CwtchLabel(label: AppLocalizations.of(context)!.serverAddress), - SizedBox( - height: 20, - ), - SelectableText( - 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), + child: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ + SizedBox( + height: 20, + ), + CwtchLabel(label: AppLocalizations.of(context)!.serverAddress), + SizedBox( + height: 20, + ), + SelectableText(serverInfoState.onion), - // Description - SizedBox( - height: 20, - ), - CwtchLabel(label: AppLocalizations.of(context)!.serverDescriptionLabel), - Text(AppLocalizations.of(context)!.serverDescriptionDescription), - SizedBox( - height: 20, - ), - CwtchButtonTextField( - controller: ctrlrDesc, - readonly: false, - tooltip: AppLocalizations.of(context)!.saveBtn, - labelText: AppLocalizations.of(context)!.fieldDescriptionLabel, - icon: Icon(Icons.save), - onPressed: () { - Provider.of(context, listen: false).cwtch.SetConversationAttribute(profile.onion, serverInfoState.identifier, "server.description", ctrlrDesc.text); - serverInfoState.updateDescription(ctrlrDesc.text); - }, - ), + // Description + SizedBox( + height: 20, + ), + CwtchLabel(label: AppLocalizations.of(context)!.serverDescriptionLabel), + Text(AppLocalizations.of(context)!.serverDescriptionDescription), + SizedBox( + height: 20, + ), + CwtchButtonTextField( + controller: ctrlrDesc, + readonly: false, + tooltip: AppLocalizations.of(context)!.saveBtn, + labelText: AppLocalizations.of(context)!.fieldDescriptionLabel, + icon: Icon(Icons.save), + onPressed: () { + Provider.of(context, listen: false).cwtch.SetConversationAttribute(profile.onion, serverInfoState.identifier, "server.description", ctrlrDesc.text); + serverInfoState.updateDescription(ctrlrDesc.text); + }, + ), - SizedBox( - height: 20, - ), + SizedBox( + height: 20, + ), - Padding(padding: EdgeInsets.all(8), child: Text( AppLocalizations.of(context)!.groupsOnThisServerLabel),), - Expanded(child: _buildGroupsList(serverInfoState)) - ]))); - - }); + 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) { - return ChangeNotifierProvider.value( - value: group, - builder: (context, child) => RepaintBoundary(child: _buildGroupRow(group)), // ServerRow()), - ); - }, + final tiles = serverInfoState.groups.map( + (ContactInfoState group) { + return ChangeNotifierProvider.value( + value: group, + builder: (context, child) => RepaintBoundary(child: _buildGroupRow(group)), // ServerRow()), + ); + }, ); final divided = ListTile.divideTiles( @@ -126,26 +125,22 @@ class _RemoteServerViewState extends State { Widget _buildGroupRow(ContactInfoState group) { return Padding( padding: const EdgeInsets.all(6.0), //border size - child: Column( - children: [ - Text( - group.nickname, - style: Provider.of(context).biggerFont.apply(color: Provider.of(context).theme.portraitOnlineBorderColor()), - softWrap: true, - overflow: TextOverflow.ellipsis, - ), - Visibility( - visible: !Provider.of(context).streamerMode, - child: ExcludeSemantics( - child: Text( - group.onion, - softWrap: true, - overflow: TextOverflow.ellipsis, - style: TextStyle(color: Provider.of(context).theme.portraitOnlineBorderColor()), - ))) - ]) - ); + child: Column(children: [ + Text( + group.nickname, + style: Provider.of(context).biggerFont.apply(color: Provider.of(context).theme.portraitOnlineBorderColor()), + softWrap: true, + overflow: TextOverflow.ellipsis, + ), + Visibility( + visible: !Provider.of(context).streamerMode, + child: ExcludeSemantics( + child: Text( + group.onion, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyle(color: Provider.of(context).theme.portraitOnlineBorderColor()), + ))) + ])); } - } - diff --git a/lib/widgets/filebubble.dart b/lib/widgets/filebubble.dart index 8054957d..a6e7c999 100644 --- a/lib/widgets/filebubble.dart +++ b/lib/widgets/filebubble.dart @@ -49,6 +49,26 @@ class FileBubbleState extends State { var borderRadiousEh = 15.0; var showFileSharing = Provider.of(context).isExperimentEnabled(FileSharingExperiment); var prettyDate = DateFormat.yMd(Platform.localeName).add_jm().format(Provider.of(context).timestamp); + var downloadComplete = Provider.of(context).downloadComplete(widget.fileKey()); + var downloadInterrupted = Provider.of(context).downloadInterrupted(widget.fileKey()); + + if (downloadInterrupted) { + Provider.of(context, listen: false).cwtch.CheckDownloadStatus(Provider.of(context, listen: false).onion, widget.fileKey()); + } + var path = Provider.of(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(context).downloadActive(widget.fileKey()); + var downloadGotManifest = Provider.of(context).downloadGotManifest(widget.fileKey()); // If the sender is not us, then we want to give them a nickname... var senderDisplayStr = ""; @@ -61,85 +81,76 @@ class FileBubbleState extends State { } } return LayoutBuilder(builder: (context, constraints) { - var wdgSender = Center( - widthFactor: 1, - child: SelectableText(senderDisplayStr + '\u202F', - style: TextStyle(fontSize: 9.0, color: fromMe ? Provider.of(context).theme.messageFromMeTextColor() : Provider.of(context).theme.messageFromOtherTextColor()))); - - var isPreview = false; - var wdgMessage = !showFileSharing - ? Text(AppLocalizations.of(context)!.messageEnableFileSharing) - : fromMe - ? senderFileChrome(AppLocalizations.of(context)!.messageFileSent, widget.nameSuggestion, widget.rootHash, widget.fileSize) - : (fileChrome(AppLocalizations.of(context)!.messageFileOffered + ":", widget.nameSuggestion, widget.rootHash, widget.fileSize, - Provider.of(context).downloadSpeed(widget.fileKey()))); - Widget wdgDecorations; - if (!showFileSharing) { - wdgDecorations = Text('\u202F'); - } else if (fromMe) { - wdgDecorations = MessageBubbleDecoration(ackd: Provider.of(context).ackd, errored: Provider.of(context).error, fromMe: fromMe, prettyDate: prettyDate); - } else if (Provider.of(context).downloadComplete(widget.fileKey())) { - // in this case, whatever marked download.complete would have also set the path - var path = Provider.of(context).downloadFinalPath(widget.fileKey())!; - 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( - myFile!, - cacheWidth: 2048, // limit the amount of space the image can decode too, we keep this high-ish to allow quality previews... - filterQuality: FilterQuality.medium, - fit: BoxFit.fill, - alignment: Alignment.center, - width: constraints.maxWidth, - isAntiAlias: false, - errorBuilder: (context, error, stackTrace) { - return MalformedBubble(); - }, - ), - onTap: () { - pop(myFile!, wdgMessage); - }, - ); - } else { - wdgDecorations = Text(AppLocalizations.of(context)!.fileSavedTo + ': ' + path + '\u202F'); - } - } else if (Provider.of(context).downloadActive(widget.fileKey())) { - if (!Provider.of(context).downloadGotManifest(widget.fileKey())) { - wdgDecorations = Text(AppLocalizations.of(context)!.retrievingManifestMessage + '\u202F'); - } else { - wdgDecorations = LinearProgressIndicator( - value: Provider.of(context).downloadProgress(widget.fileKey()), - color: Provider.of(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 - if (!Provider.of(context).downloadInterrupted(widget.fileKey())) { - wdgDecorations = Text(AppLocalizations.of(context)!.fileCheckingStatus + '...' + '\u202F'); - Provider.of(context, listen: false).cwtch.CheckDownloadStatus(Provider.of(context, listen: false).onion, widget.fileKey()); - } else { - var path = Provider.of(context).downloadFinalPath(widget.fileKey()) ?? ""; - wdgDecorations = Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(AppLocalizations.of(context)!.fileInterrupted + ': ' + path + '\u202F'), - ElevatedButton(onPressed: _btnResume, child: Text(AppLocalizations.of(context)!.verfiyResumeButton)) - ]); - } - } else { - wdgDecorations = Center( + var wdgSender = Center( widthFactor: 1, - child: Wrap(children: [ - Padding(padding: EdgeInsets.all(5), child: ElevatedButton(child: Text(AppLocalizations.of(context)!.downloadFileButton + '\u202F'), onPressed: _btnAccept)), - ])); - } + child: SelectableText(senderDisplayStr + '\u202F', + style: TextStyle(fontSize: 9.0, color: fromMe ? Provider.of(context).theme.messageFromMeTextColor() : Provider.of(context).theme.messageFromOtherTextColor()))); + var isPreview = false; + var wdgMessage = !showFileSharing + ? Text(AppLocalizations.of(context)!.messageEnableFileSharing) + : fromMe + ? senderFileChrome(AppLocalizations.of(context)!.messageFileSent, widget.nameSuggestion, widget.rootHash, widget.fileSize) + : (fileChrome(AppLocalizations.of(context)!.messageFileOffered + ":", widget.nameSuggestion, widget.rootHash, widget.fileSize, + Provider.of(context).downloadSpeed(widget.fileKey()))); + Widget wdgDecorations; + if (!showFileSharing) { + wdgDecorations = Text('\u202F'); + } else if (fromMe) { + wdgDecorations = MessageBubbleDecoration(ackd: Provider.of(context).ackd, errored: Provider.of(context).error, fromMe: fromMe, prettyDate: prettyDate); + } else if (downloadComplete) { + // in this case, whatever marked download.complete would have also set the path + var lpath = path!.toLowerCase(); + if (lpath.endsWith("jpg") || lpath.endsWith("jpeg") || lpath.endsWith("png") || lpath.endsWith("gif") || lpath.endsWith("webp") || lpath.endsWith("bmp")) { + isPreview = true; + wdgDecorations = GestureDetector( + child: Image.file( + myFile!, + cacheWidth: 2048, // limit the amount of space the image can decode too, we keep this high-ish to allow quality previews... + filterQuality: FilterQuality.medium, + fit: BoxFit.fill, + alignment: Alignment.center, + width: constraints.maxWidth, + isAntiAlias: false, + errorBuilder: (context, error, stackTrace) { + return MalformedBubble(); + }, + ), + onTap: () { + pop(myFile!, wdgMessage); + }, + ); + } else { + wdgDecorations = Text(AppLocalizations.of(context)!.fileSavedTo + ': ' + path + '\u202F'); + } + } else if (downloadActive) { + if (!downloadGotManifest) { + wdgDecorations = Text(AppLocalizations.of(context)!.retrievingManifestMessage + '\u202F'); + } else { + wdgDecorations = LinearProgressIndicator( + value: Provider.of(context).downloadProgress(widget.fileKey()), + color: Provider.of(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 + if (!downloadInterrupted) { + wdgDecorations = Text(AppLocalizations.of(context)!.fileCheckingStatus + '...' + '\u202F'); + } else { + var path = Provider.of(context).downloadFinalPath(widget.fileKey()) ?? ""; + wdgDecorations = Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Text(AppLocalizations.of(context)!.fileInterrupted + ': ' + path + '\u202F'), + ElevatedButton(onPressed: _btnResume, child: Text(AppLocalizations.of(context)!.verfiyResumeButton)) + ]); + } + } else { + wdgDecorations = Center( + widthFactor: 1, + child: Wrap(children: [ + Padding(padding: EdgeInsets.all(5), child: ElevatedButton(child: Text(AppLocalizations.of(context)!.downloadFileButton + '\u202F'), onPressed: _btnAccept)), + ])); + } return Container( constraints: constraints, @@ -193,7 +204,7 @@ class FileBubbleState extends State { Provider.of(context, listen: false).downloadInit(widget.fileKey(), (widget.fileSize / 4096).ceil()); Provider.of(context, listen: false).cwtch.SetMessageAttribute(profileOnion, conversation, 0, idx, "file-downloaded", "true"); //Provider.of(context, listen: false).flags |= 0x02; - ContactInfoState? contact = Provider.of(context).contactList.findContact(Provider.of(context).senderHandle); + ContactInfoState? contact = Provider.of(context, listen: false).contactList.findContact(Provider.of(context).senderHandle); if (contact != null) { Provider.of(context, listen: false).cwtch.DownloadFile(profileOnion, contact.identifier, file.path, manifestPath, widget.fileKey()); } diff --git a/lib/widgets/folderpicker.dart b/lib/widgets/folderpicker.dart index 4e6d146f..7e9f9bfd 100644 --- a/lib/widgets/folderpicker.dart +++ b/lib/widgets/folderpicker.dart @@ -28,40 +28,40 @@ class _CwtchFolderPickerState extends State { @override Widget build(BuildContext context) { return Container( - margin: EdgeInsets.all(10), - padding: EdgeInsets.all(2), - child: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ - CwtchLabel(label: widget.label), - SizedBox( - height: 20, - ), - CwtchButtonTextField( - controller: ctrlrVal, - readonly: Platform.isAndroid, - onPressed: () async { - if (Platform.isAndroid) { - return; - } - - try { - var selectedDirectory = await getDirectoryPath(); - if (selectedDirectory != null) { - //File directory = File(selectedDirectory); - selectedDirectory += "/"; - ctrlrVal.text = selectedDirectory; - if (widget.onSave != null) { - widget.onSave!(selectedDirectory); + margin: EdgeInsets.all(10), + padding: EdgeInsets.all(2), + child: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ + CwtchLabel(label: widget.label), + SizedBox( + height: 20, + ), + CwtchButtonTextField( + controller: ctrlrVal, + readonly: Platform.isAndroid, + onPressed: () async { + if (Platform.isAndroid) { + return; } - } else { - // User canceled the picker - } - } catch (e) { - print(e); - } - }, - icon: Icon(Icons.folder), - tooltip: "Browse",//todo: l18n - ) - ])); + + try { + var selectedDirectory = await getDirectoryPath(); + if (selectedDirectory != null) { + //File directory = File(selectedDirectory); + selectedDirectory += "/"; + ctrlrVal.text = selectedDirectory; + if (widget.onSave != null) { + widget.onSave!(selectedDirectory); + } + } else { + // User canceled the picker + } + } catch (e) { + print(e); + } + }, + icon: Icon(Icons.folder), + tooltip: "Browse", //todo: l18n + ) + ])); } } diff --git a/lib/widgets/remoteserverrow.dart b/lib/widgets/remoteserverrow.dart index 339a170d..b3c2f356 100644 --- a/lib/widgets/remoteserverrow.dart +++ b/lib/widgets/remoteserverrow.dart @@ -23,46 +23,42 @@ class _RemoteServerRowState extends State { @override Widget build(BuildContext context) { var server = Provider.of(context); - var description = server.description.isNotEmpty ? server.description : server.onion; + var description = server.description.isNotEmpty ? server.description : server.onion; var running = server.status == "Synced"; - return Consumer( - builder: (context, profile, child) { - return Card(clipBehavior: Clip.antiAlias, + return Consumer(builder: (context, profile, child) { + return Card( + clipBehavior: Clip.antiAlias, margin: EdgeInsets.all(0.0), child: InkWell( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + Padding( + padding: const EdgeInsets.all(6.0), //border size + child: Icon(CwtchIcons.dns_24px, + color: running ? Provider.of(context).theme.portraitOnlineBorderColor() : Provider.of(context).theme.portraitOfflineBorderColor(), size: 64)), + Expanded( + child: Column( children: [ - Padding( - padding: const EdgeInsets.all(6.0), //border size - child: Icon(CwtchIcons.dns_24px, - color: running ? Provider.of(context).theme.portraitOnlineBorderColor() : Provider.of(context).theme.portraitOfflineBorderColor(), - size: 64) - + Text( + description, + semanticsLabel: description, + style: Provider.of(context) + .biggerFont + .apply(color: running ? Provider.of(context).theme.portraitOnlineBorderColor() : Provider.of(context).theme.portraitOfflineBorderColor()), + softWrap: true, + overflow: TextOverflow.ellipsis, ), - Expanded( - child: Column( - children: [ - Text( - description, - semanticsLabel: description, - style: Provider.of(context).biggerFont.apply(color: running ? Provider.of(context).theme.portraitOnlineBorderColor() : Provider.of(context).theme.portraitOfflineBorderColor()), - softWrap: true, - overflow: TextOverflow.ellipsis, - ), - Visibility( - visible: !Provider.of(context).streamerMode, - child: ExcludeSemantics( - child: Text( - server.onion, - softWrap: true, - overflow: TextOverflow.ellipsis, - style: TextStyle(color: running ? Provider.of(context).theme.portraitOnlineBorderColor() : Provider.of(context).theme.portraitOfflineBorderColor()), - ))) - ], - )), - - ]), + Visibility( + visible: !Provider.of(context).streamerMode, + child: ExcludeSemantics( + child: Text( + server.onion, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyle(color: running ? Provider.of(context).theme.portraitOnlineBorderColor() : Provider.of(context).theme.portraitOfflineBorderColor()), + ))) + ], + )), + ]), onTap: () { Navigator.of(context).push(MaterialPageRoute( settings: RouteSettings(name: "remoteserverview"), @@ -72,7 +68,7 @@ class _RemoteServerRowState extends State { child: RemoteServerView(), ); })); - } - ));}); - } + })); + }); + } } diff --git a/lib/widgets/serverrow.dart b/lib/widgets/serverrow.dart index a4e8bb05..65edb974 100644 --- a/lib/widgets/serverrow.dart +++ b/lib/widgets/serverrow.dart @@ -26,58 +26,57 @@ class _ServerRowState extends State { margin: EdgeInsets.all(0.0), child: InkWell( child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Padding( - padding: const EdgeInsets.all(6.0), //border size - child: Icon(CwtchIcons.dns_24px, - color: server.running ? Provider.of(context).theme.portraitOnlineBorderColor() : Provider.of(context).theme.portraitOfflineBorderColor(), size: 64)), - Expanded( - child: Column( - children: [ - Text( - server.description, - semanticsLabel: server.description, - style: Provider.of(context) - .biggerFont - .apply(color: server.running ? Provider.of(context).theme.portraitOnlineBorderColor() : Provider.of(context).theme.portraitOfflineBorderColor()), - softWrap: true, - overflow: TextOverflow.ellipsis, - ), - Visibility( - visible: !Provider.of(context).streamerMode, - child: ExcludeSemantics( - child: Text( - server.onion, + Padding( + padding: const EdgeInsets.all(6.0), //border size + child: Icon(CwtchIcons.dns_24px, + color: server.running ? Provider.of(context).theme.portraitOnlineBorderColor() : Provider.of(context).theme.portraitOfflineBorderColor(), size: 64)), + Expanded( + child: Column( + children: [ + Text( + server.description, + semanticsLabel: server.description, + style: Provider.of(context) + .biggerFont + .apply(color: server.running ? Provider.of(context).theme.portraitOnlineBorderColor() : Provider.of(context).theme.portraitOfflineBorderColor()), softWrap: true, overflow: TextOverflow.ellipsis, - style: TextStyle(color: server.running ? Provider.of(context).theme.portraitOnlineBorderColor() : Provider.of(context).theme.portraitOfflineBorderColor()), - ))) - ], - )), + ), + Visibility( + visible: !Provider.of(context).streamerMode, + child: ExcludeSemantics( + child: Text( + server.onion, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyle(color: server.running ? Provider.of(context).theme.portraitOnlineBorderColor() : Provider.of(context).theme.portraitOfflineBorderColor()), + ))) + ], + )), - // Copy server button - IconButton( - enableFeedback: true, - tooltip: AppLocalizations.of(context)!.copyServerKeys, - icon: Icon(CwtchIcons.address_copy_2, color: Provider.of(context).current().mainTextColor()), - onPressed: () { - Clipboard.setData(new ClipboardData(text: server.serverBundle)); - }, - ), + // Copy server button + IconButton( + enableFeedback: true, + tooltip: AppLocalizations.of(context)!.copyServerKeys, + icon: Icon(CwtchIcons.address_copy_2, color: Provider.of(context).current().mainTextColor()), + onPressed: () { + Clipboard.setData(new ClipboardData(text: server.serverBundle)); + }, + ), - // Edit button - IconButton( - enableFeedback: true, - tooltip: AppLocalizations.of(context)!.editServerTitle, - icon: Icon(Icons.create, color: Provider.of(context).current().mainTextColor()), - onPressed: () { + // Edit button + IconButton( + enableFeedback: true, + tooltip: AppLocalizations.of(context)!.editServerTitle, + icon: Icon(Icons.create, color: Provider.of(context).current().mainTextColor()), + onPressed: () { + _pushEditServer(server); + }, + ) + ]), + onTap: () { _pushEditServer(server); - }, - ) - ]), - onTap: () { - _pushEditServer(server); - } - )); + })); } void _pushEditServer(ServerInfoState server) {