Merge pull request 'Format, Context Binding and Check if File Exists in File Bubble' (#447) from file-fixes into trunk
continuous-integration/drone/push Build is pending Details

Reviewed-on: #447
Reviewed-by: Dan Ballard <dan@openprivacy.ca>
This commit is contained in:
Sarah Jamie Lewis 2022-04-26 19:38:28 +00:00
commit 9d8f73ac00
10 changed files with 66 additions and 35 deletions

View File

@ -215,8 +215,9 @@ class CwtchFfi implements Cwtch {
// ignore: non_constant_identifier_names
final StartCwtch = startCwtchC.asFunction<StartCwtchFn>();
final ut8CwtchDir = cwtchDir.toNativeUtf8();
StartCwtch(ut8CwtchDir, ut8CwtchDir.length, bundledTor.toNativeUtf8(), bundledTor.length);
final utf8CwtchDir = cwtchDir.toNativeUtf8();
StartCwtch(utf8CwtchDir, utf8CwtchDir.length, bundledTor.toNativeUtf8(), bundledTor.length);
malloc.free(utf8CwtchDir);
// Spawn an isolate to listen to events from libcwtch-go and then dispatch them when received on main thread to cwtchNotifier
cwtchIsolate = await Isolate.spawn(_checkAppbusEvents, _receivePort.sendPort);
@ -326,6 +327,7 @@ class CwtchFfi implements Cwtch {
String jsonMessage = jsonMessageBytes.toDartString();
_UnsafeFreePointerAnyUseOfThisFunctionMustBeDoubleApproved(jsonMessageBytes);
malloc.free(utf8profile);
return jsonMessage;
}

View File

@ -103,7 +103,7 @@ class MessageCache extends ChangeNotifier {
void addFrontIndexGap(int count, int lastSeenId) {
// scan across indexed message the unread count amount (that's the last time UI/BE acked a message)
// if we find the last seen ID, the diff of unread count is what's unsynced
for(var i = 0; i < (count+1) && i < cacheByIndex.length; i++) {
for (var i = 0; i < (count + 1) && i < cacheByIndex.length; i++) {
if (this.cacheByIndex[i].messageId == lastSeenId) {
// we have found the matching lastSeenId so we can calculate the unsynced as the unread messages before it
this._indexUnsynced = count - i;
@ -114,7 +114,7 @@ class MessageCache extends ChangeNotifier {
// we did not find a matching index, diff to the back end is too great, reset index cache
resetIndexCache();
}
int get indexUnsynced => _indexUnsynced;
void resetIndexCache() {

View File

@ -350,4 +350,9 @@ class ProfileInfoState extends ChangeNotifier {
int cacheMemUsage() {
return _contacts.cacheMemUsage();
}
void downloadReset(String fileKey) {
this._downloads.remove(fileKey);
notifyListeners();
}
}

View File

@ -73,10 +73,10 @@ class LinuxNotificationsManager implements NotificationsManager {
// Cwtch can install in non flutter supported ways on linux, this code detects where the assets are on Linux
Future<String> detectLinuxAssetsPath() async {
var devStat = FileStat.stat("assets");
var localStat = FileStat.stat("data/flutter_assets");
var homeStat = FileStat.stat((Platform.environment["HOME"] ?? "") + "/.local/share/cwtch/data/flutter_assets");
var rootStat = FileStat.stat("/usr/share/cwtch/data/flutter_assets");
var devStat = FileStat.stat("assets");
var localStat = FileStat.stat("data/flutter_assets");
var homeStat = FileStat.stat((Platform.environment["HOME"] ?? "") + "/.local/share/cwtch/data/flutter_assets");
var rootStat = FileStat.stat("/usr/share/cwtch/data/flutter_assets");
if ((await devStat).type == FileSystemEntityType.directory) {
return Directory.current.path; //appPath;
@ -94,7 +94,7 @@ class LinuxNotificationsManager implements NotificationsManager {
var iconPath = Uri.file(path.join(assetsPath, "assets/knott.png"));
client.notify(message, appName: "cwtch", appIcon: iconPath.toString(), replacesId: this.previous_id).then((linux_notifications.Notification value) async {
previous_id = value.id;
if ((await value.closeReason) == linux_notifications.NotificationClosedReason.dismissed) {
if ((await value.closeReason) == linux_notifications.NotificationClosedReason.dismissed) {
this.notificationSelectConvo(profile, conversationId);
}
});
@ -115,9 +115,9 @@ class NotificationPayload {
convoId = json['convoId'];
Map<String, dynamic> toJson() => {
'profileOnion': profileOnion,
'convoId': convoId,
};
'profileOnion': profileOnion,
'convoId': convoId,
};
}
// FlutterLocalNotificationsPlugin based NotificationManager that handles MacOS
@ -138,10 +138,10 @@ class NixNotificationManager implements NotificationsManager {
final InitializationSettings initializationSettings = InitializationSettings(android: null, iOS: null, macOS: initializationSettingsMacOS, linux: initializationSettingsLinux);
scheduleMicrotask(() async {
flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<MacOSFlutterLocalNotificationsPlugin>()?.requestPermissions(
alert: true,
badge: false,
sound: false,
);
alert: true,
badge: false,
sound: false,
);
await flutterLocalNotificationsPlugin.initialize(initializationSettings, onSelectNotification: selectNotification);
});

View File

@ -130,7 +130,10 @@ class _ContactsViewState extends State<ContactsView> {
floatingActionButton: FloatingActionButton(
onPressed: _modalAddImportChoice,
tooltip: AppLocalizations.of(context)!.tooltipAddContact,
child: Icon(CwtchIcons.person_add_alt_1_24px, color: Provider.of<Settings>(context).theme.defaultButtonTextColor,),
child: Icon(
CwtchIcons.person_add_alt_1_24px,
color: Provider.of<Settings>(context).theme.defaultButtonTextColor,
),
),
body: showSearchBar || Provider.of<ContactListState>(context).isFiltered ? _buildFilterable() : _buildContactList());
}

View File

@ -464,7 +464,7 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
Visibility(
visible: EnvironmentConfig.BUILD_VER == dev_version && !Platform.isAndroid,
child: FutureBuilder(
future: EnvironmentConfig.BUILD_VER != dev_version ||Platform.isAndroid ? null : Provider.of<FlwtchState>(context).cwtch.GetDebugInfo(),
future: EnvironmentConfig.BUILD_VER != dev_version || Platform.isAndroid ? null : Provider.of<FlwtchState>(context).cwtch.GetDebugInfo(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Column(

View File

@ -183,7 +183,9 @@ class _GroupSettingsViewState extends State<GroupSettingsView> {
onPressed: () {
showAlertDialog(context);
},
style: ButtonStyle(backgroundColor: MaterialStateProperty.all(Provider.of<Settings>(context).theme.backgroundPaneColor), foregroundColor: MaterialStateProperty.all(Provider.of<Settings>(context).theme.mainTextColor)),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Provider.of<Settings>(context).theme.backgroundPaneColor),
foregroundColor: MaterialStateProperty.all(Provider.of<Settings>(context).theme.mainTextColor)),
icon: Icon(CwtchIcons.leave_group),
label: Text(
AppLocalizations.of(context)!.leaveConversation,

View File

@ -269,7 +269,9 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
onPressed: () {
showAlertDialog(context);
},
style: ButtonStyle(backgroundColor: MaterialStateProperty.all(Provider.of<Settings>(context).theme.backgroundPaneColor), foregroundColor: MaterialStateProperty.all(Provider.of<Settings>(context).theme.mainTextColor)),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Provider.of<Settings>(context).theme.backgroundPaneColor),
foregroundColor: MaterialStateProperty.all(Provider.of<Settings>(context).theme.mainTextColor)),
icon: Icon(CwtchIcons.leave_group),
label: Text(
AppLocalizations.of(context)!.leaveConversation,

View File

@ -48,7 +48,7 @@ class FileBubbleState extends State<FileBubble> {
Widget build(BuildContext context) {
var fromMe = Provider.of<MessageMetadata>(context).senderHandle == Provider.of<ProfileInfoState>(context).onion;
var flagStarted = Provider.of<MessageMetadata>(context).attributes["file-downloaded"] == "true";
var borderRadiousEh = 15.0;
var borderRadius = 15.0;
var showFileSharing = Provider.of<Settings>(context).isExperimentEnabled(FileSharingExperiment);
DateTime messageDate = Provider.of<MessageMetadata>(context).timestamp;
@ -56,7 +56,7 @@ class FileBubbleState extends State<FileBubble> {
var path = Provider.of<ProfileInfoState>(context).downloadFinalPath(widget.fileKey());
// If we haven't stored the filepath in message attributes then save it
if (metadata.attributes["filepath"] != null) {
if (metadata.attributes["filepath"] != null && metadata.attributes["filepath"].toString().isNotEmpty) {
path = metadata.attributes["filepath"];
} else if (path != null && metadata.attributes["filepath"] == null) {
Provider.of<FlwtchState>(context).cwtch.SetMessageAttribute(metadata.profileOnion, metadata.conversationIdentifier, 0, metadata.messageID, "filepath", path);
@ -72,6 +72,21 @@ class FileBubbleState extends State<FileBubble> {
if (myFile == null) {
setState(() {
myFile = new File(path!);
// reset
if (myFile?.existsSync() == false) {
myFile = null;
Provider.of<ProfileInfoState>(context).downloadReset(widget.fileKey());
Provider.of<MessageMetadata>(context).attributes["filepath"] = null;
Provider.of<MessageMetadata>(context).attributes["file-downloaded"] = "false";
Provider.of<MessageMetadata>(context).attributes["file-missing"] = "true";
Provider.of<FlwtchState>(context).cwtch.SetMessageAttribute(metadata.profileOnion, metadata.conversationIdentifier, 0, metadata.messageID, "file-downloaded", "false");
Provider.of<FlwtchState>(context).cwtch.SetMessageAttribute(metadata.profileOnion, metadata.conversationIdentifier, 0, metadata.messageID, "filepath", "");
Provider.of<FlwtchState>(context).cwtch.SetMessageAttribute(metadata.profileOnion, metadata.conversationIdentifier, 0, metadata.messageID, "file-missing", "true");
} else {
Provider.of<MessageMetadata>(context).attributes["file-missing"] = "false";
Provider.of<FlwtchState>(context).cwtch.SetMessageAttribute(metadata.profileOnion, metadata.conversationIdentifier, 0, metadata.messageID, "file-missing", "false");
}
});
}
}
@ -122,7 +137,7 @@ class FileBubbleState extends State<FileBubble> {
padding: EdgeInsets.all(1.0),
child: Image.file(
myFile!,
cacheWidth: 2048,
cacheWidth: (MediaQuery.of(bcontext).size.width * 0.6).floor(),
// limit the amount of space the image can decode too, we keep this high-ish to allow quality previews...
filterQuality: FilterQuality.medium,
fit: BoxFit.scaleDown,
@ -167,7 +182,9 @@ class FileBubbleState extends State<FileBubble> {
}
} else if (!senderIsContact) {
wdgDecorations = Text(AppLocalizations.of(context)!.msgAddToAccept);
} else if (!widget.isAuto) {
} else if (!widget.isAuto || Provider.of<MessageMetadata>(context).attributes["file-missing"] == "false") {
//Note: we need this second case to account for scenarios where a user deletes the downloaded file, we won't automatically
// fetch it again, so we need to offer the user the ability to restart..
wdgDecorations = Visibility(
visible: widget.interactive,
child: Center(
@ -185,10 +202,10 @@ class FileBubbleState extends State<FileBubble> {
color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeBackgroundColor : Provider.of<Settings>(context).theme.messageFromOtherBackgroundColor,
border: Border.all(color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeBackgroundColor : Provider.of<Settings>(context).theme.messageFromOtherBackgroundColor, width: 1),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(borderRadiousEh),
topRight: Radius.circular(borderRadiousEh),
bottomLeft: fromMe ? Radius.circular(borderRadiousEh) : Radius.zero,
bottomRight: fromMe ? Radius.zero : Radius.circular(borderRadiousEh),
topLeft: Radius.circular(borderRadius),
topRight: Radius.circular(borderRadius),
bottomLeft: fromMe ? Radius.circular(borderRadius) : Radius.zero,
bottomRight: fromMe ? Radius.zero : Radius.circular(borderRadius),
),
),
child: Padding(

View File

@ -118,37 +118,37 @@ class MessageBubbleState extends State<MessageBubble> {
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(AppLocalizations.of(context)!.clickableLinksWarning),
Text(AppLocalizations.of(bcontext)!.clickableLinksWarning),
Flex(direction: Axis.horizontal, mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[
Container(
margin: EdgeInsets.symmetric(vertical: 20, horizontal: 10),
child: ElevatedButton(
child: Text(AppLocalizations.of(context)!.clickableLinksCopy, semanticsLabel: AppLocalizations.of(context)!.clickableLinksCopy),
child: Text(AppLocalizations.of(bcontext)!.clickableLinksCopy, semanticsLabel: AppLocalizations.of(bcontext)!.clickableLinksCopy),
onPressed: () {
Clipboard.setData(new ClipboardData(text: link.url));
final snackBar = SnackBar(
content: Text(AppLocalizations.of(context)!.copiedToClipboardNotification),
content: Text(AppLocalizations.of(bcontext)!.copiedToClipboardNotification),
);
Navigator.pop(bcontext);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
ScaffoldMessenger.of(bcontext).showSnackBar(snackBar);
},
),
),
Container(
margin: EdgeInsets.symmetric(vertical: 20, horizontal: 10),
child: ElevatedButton(
child: Text(AppLocalizations.of(context)!.clickableLinkOpen, semanticsLabel: AppLocalizations.of(context)!.clickableLinkOpen),
child: Text(AppLocalizations.of(bcontext)!.clickableLinkOpen, semanticsLabel: AppLocalizations.of(bcontext)!.clickableLinkOpen),
onPressed: () async {
if (await canLaunch(link.url)) {
await launch(link.url);
Navigator.pop(bcontext);
} else {
final snackBar = SnackBar(
content: Text(AppLocalizations.of(context)!.clickableLinkError),
content: Text(AppLocalizations.of(bcontext)!.clickableLinkError),
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
ScaffoldMessenger.of(bcontext).showSnackBar(snackBar);
}
},
),