diff --git a/lib/view/pages/files/fileUploadDialog.dart b/lib/view/pages/files/fileUploadDialog.dart index 03c1697..d48a3e7 100644 --- a/lib/view/pages/files/fileUploadDialog.dart +++ b/lib/view/pages/files/fileUploadDialog.dart @@ -43,7 +43,6 @@ class _FileUploadDialogState extends State<FileUploadDialog> { setState(() { state = FileUploadState.checkConflict; }); - //await (await WebdavApi.webdav).mkcol(widget.remotePath.join("/")); // TODO is this needed? It does not work anymore... List<WebDavResponse> result = (await webdavClient.propfind(widget.remotePath.join("/"))).responses; if(result.any((element) => element.href!.endsWith("/$targetFileName"))) { setState(() { diff --git a/lib/view/pages/talk/chatBubble.dart b/lib/view/pages/talk/chatBubble.dart index ba7a61e..5275852 100644 --- a/lib/view/pages/talk/chatBubble.dart +++ b/lib/view/pages/talk/chatBubble.dart @@ -177,32 +177,41 @@ class _ChatBubbleState extends State<ChatBubble> { onLongPress: () { showDialog(context: context, builder: (context) { List<String> commonReactions = ["👍", "👎", "😆", "❤️", "💔", "😍"]; + bool reactable = widget.bubbleData.messageType == GetRoomResponseObjectMessageType.comment; return SimpleDialog( children: [ - Wrap( - alignment: WrapAlignment.center, - children: [ - ...commonReactions.map((e) => TextButton( - style: TextButton.styleFrom( - padding: EdgeInsets.zero, - tapTargetSize: MaterialTapTargetSize.shrinkWrap, - minimumSize: const Size(40, 40) - ), - onPressed: () { - Navigator.of(context).pop(); - ReactMessage( - chatToken: widget.chatData.token, - messageId: widget.bubbleData.id, - params: ReactMessageParams(e), - ).run().then((value) => widget.refetch(renew: true)); - }, - child: Text(e)), - ), - ], - ), - const Divider(), Visibility( - visible: true, + visible: reactable, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Wrap( + alignment: WrapAlignment.center, + children: [ + ...commonReactions.map((e) => TextButton( + style: TextButton.styleFrom( + padding: EdgeInsets.zero, + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + minimumSize: const Size(40, 40) + ), + onPressed: () { + Navigator.of(context).pop(); + ReactMessage( + chatToken: widget.chatData.token, + messageId: widget.bubbleData.id, + params: ReactMessageParams(e), + ).run().then((value) => widget.refetch(renew: true)); + }, + child: Text(e)), + ), + ], + ), + const Divider(), + ], + ) + ), + Visibility( + visible: reactable, child: ListTile( leading: const Icon(Icons.add_reaction_outlined), title: const Text("Reaktionen"), @@ -215,7 +224,7 @@ class _ChatBubbleState extends State<ChatBubble> { ), ), Visibility( - visible: !message.containsFile && widget.bubbleData.messageType == GetRoomResponseObjectMessageType.comment, + visible: !message.containsFile, child: ListTile( leading: const Icon(Icons.copy), title: const Text("Nachricht kopieren"), @@ -234,7 +243,7 @@ class _ChatBubbleState extends State<ChatBubble> { ), ), Visibility( - visible: widget.isSender, + visible: widget.isSender && DateTime.fromMillisecondsSinceEpoch(widget.bubbleData.timestamp * 1000).add(const Duration(hours: 6)).isAfter(DateTime.now()), child: ListTile( leading: const Icon(Icons.delete_outline), title: const Text("Nachricht löschen"), diff --git a/lib/view/pages/talk/chatMessage.dart b/lib/view/pages/talk/chatMessage.dart index b4aee4b..2ecd0d7 100644 --- a/lib/view/pages/talk/chatMessage.dart +++ b/lib/view/pages/talk/chatMessage.dart @@ -30,7 +30,7 @@ class ChatMessage { Widget getWidget() { if(file == null) { - return SelectableLinkify( + return Linkify( text: content, onOpen: onOpen, ); @@ -49,10 +49,7 @@ class ChatMessage { placeholder: (context, url) { return const Padding(padding: EdgeInsets.all(10), child: CircularProgressIndicator()); }, - imageUrl: "https://${EndpointData().nextcloud().full()}/core/preview?fileId=${file!.id}&x=100&y=-1&a=1", - httpHeaders: { - "Authorization": "Basic ${AccountData().buildHttpAuthString()}" - }, + imageUrl: "https://${AccountData().buildHttpAuthString()}@${EndpointData().nextcloud().full()}/index.php/core/preview?fileId=${file!.id}&x=100&y=-1&a=1", ); } diff --git a/lib/view/pages/talk/chatTextfield.dart b/lib/view/pages/talk/chatTextfield.dart index 08cdeb3..3f1ad50 100644 --- a/lib/view/pages/talk/chatTextfield.dart +++ b/lib/view/pages/talk/chatTextfield.dart @@ -1,4 +1,5 @@ +import 'dart:io'; import 'package:flutter/material.dart'; import 'package:loader_overlay/loader_overlay.dart'; import 'package:provider/provider.dart'; @@ -8,6 +9,7 @@ import '../../../api/marianumcloud/files-sharing/fileSharingApi.dart'; import '../../../api/marianumcloud/files-sharing/fileSharingApiParams.dart'; import '../../../api/marianumcloud/talk/sendMessage/sendMessage.dart'; import '../../../api/marianumcloud/talk/sendMessage/sendMessageParams.dart'; +import '../../../api/marianumcloud/webdav/webdavApi.dart'; import '../../../model/chatList/chatProps.dart'; import '../../../widget/filePick.dart'; import '../files/fileUploadDialog.dart'; @@ -38,6 +40,10 @@ class _ChatTextfieldState extends State<ChatTextfield> { String filename = "${path.split("/").last.split(".").first}-${const Uuid().v4()}.${path.split(".").last}"; String shareFolder = "MarianumMobile"; + WebdavApi.webdav.then((webdav) { + webdav.mkcol("/$shareFolder"); + }); + showDialog(context: context, builder: (context) => FileUploadDialog( doShowFinish: false, fileName: filename, @@ -45,9 +51,9 @@ class _ChatTextfieldState extends State<ChatTextfield> { remotePath: [shareFolder], onUploadFinished: () { FileSharingApi().share(FileSharingApiParams( - shareType: 10, - shareWith: widget.sendToToken, - path: "$shareFolder/$filename", + shareType: 10, + shareWith: widget.sendToToken, + path: "$shareFolder/$filename", )).then((value) => _query()); }, ), barrierDismissible: false); @@ -81,16 +87,19 @@ class _ChatTextfieldState extends State<ChatTextfield> { Navigator.of(context).pop(); }, ), - ListTile( - leading: const Icon(Icons.image), - title: const Text("Aus Gallerie auswählen"), - onTap: () { - context.loaderOverlay.show(); - FilePick.galleryPick().then((value) { - mediaUpload(value?.path); - }); - Navigator.of(context).pop(); - }, + Visibility( + visible: !Platform.isIOS, + child: ListTile( + leading: const Icon(Icons.image), + title: const Text("Aus Gallerie auswählen"), + onTap: () { + context.loaderOverlay.show(); + FilePick.galleryPick().then((value) { + mediaUpload(value?.path); + }); + Navigator.of(context).pop(); + }, + ), ), ], ); diff --git a/lib/view/pages/talk/chatTile.dart b/lib/view/pages/talk/chatTile.dart index fe2088c..f4e7327 100644 --- a/lib/view/pages/talk/chatTile.dart +++ b/lib/view/pages/talk/chatTile.dart @@ -48,10 +48,12 @@ class _ChatTileState extends State<ChatTile> { @override Widget build(BuildContext context) { + bool useRemotePicture = widget.data.type == GetRoomResponseObjectConversationType.oneToOne; CircleAvatar circleAvatar = CircleAvatar( - foregroundImage: widget.data.type == GetRoomResponseObjectConversationType.oneToOne ? Image.network("https://${EndpointData().nextcloud().full()}/avatar/${widget.data.name}/128").image : null, + foregroundImage: useRemotePicture ? Image.network("https://${EndpointData().nextcloud().full()}/avatar/${widget.data.name}/128").image : null, backgroundColor: Theme.of(context).primaryColor, foregroundColor: Colors.white, + onForegroundImageError: useRemotePicture ? (o, t) {} : null, child: widget.data.type == GetRoomResponseObjectConversationType.group ? const Icon(Icons.group) : const Icon(Icons.person), ); diff --git a/lib/view/pages/talk/chatView.dart b/lib/view/pages/talk/chatView.dart index 71ee2b9..8b84125 100644 --- a/lib/view/pages/talk/chatView.dart +++ b/lib/view/pages/talk/chatView.dart @@ -57,13 +57,21 @@ class _ChatViewState extends State<ChatView> { lastDate = elementDate; messages.add(ChatBubble( context: context, - isSender: true, + isSender: false, bubbleData: GetChatResponseObject.getDateDummy(element.timestamp), chatData: widget.room, refetch: _query, )); } - messages.add(ChatBubble(context: context, isSender: element.actorId == widget.selfId, bubbleData: element, chatData: widget.room, refetch: _query)); + messages.add( + ChatBubble( + context: context, + isSender: element.actorId == widget.selfId && element.messageType == GetRoomResponseObjectMessageType.comment, + bubbleData: element, + chatData: widget.room, + refetch: _query + ) + ); }); } diff --git a/lib/view/pages/talk/messageReactions.dart b/lib/view/pages/talk/messageReactions.dart index cdfbce0..f7b3086 100644 --- a/lib/view/pages/talk/messageReactions.dart +++ b/lib/view/pages/talk/messageReactions.dart @@ -7,6 +7,7 @@ import '../../../api/marianumcloud/talk/getReactions/getReactionsResponse.dart'; import '../../../model/accountData.dart'; import '../../../widget/centeredLeading.dart'; import '../../../widget/loadingSpinner.dart'; +import '../../../widget/placeholderView.dart'; import '../../../widget/unimplementedDialog.dart'; class MessageReactions extends StatefulWidget { @@ -36,7 +37,8 @@ class _MessageReactionsState extends State<MessageReactions> { body: FutureBuilder( future: data, builder: (context, snapshot) { - if(snapshot.data == null) return const LoadingSpinner(); + if(snapshot.connectionState == ConnectionState.waiting) return const LoadingSpinner(); + if(snapshot.data == null) return const PlaceholderView(icon: Icons.search_off_outlined, text: "Keine Reaktionen gefunden!"); return ListView( children: [ ...snapshot.data!.data.entries.map<Widget>((entry) {