From 75cd6f1f233c5303b4d593690f50510168a5dcfe Mon Sep 17 00:00:00 2001 From: Christian Pauly Date: Sat, 17 Oct 2020 09:29:27 +0200 Subject: [PATCH] feat: Implement linux desktop notifications --- lib/components/avatar.dart | 49 ++++++++++++++------- lib/components/content_banner.dart | 17 +++----- lib/components/image_bubble.dart | 17 +++----- lib/components/input_bar.dart | 17 +++----- lib/components/matrix.dart | 61 +++++++++++++++++++-------- lib/components/message_reactions.dart | 14 ++---- lib/views/settings_emotes.dart | 19 +++------ pubspec.lock | 4 +- pubspec.yaml | 3 +- 9 files changed, 106 insertions(+), 95 deletions(-) diff --git a/lib/components/avatar.dart b/lib/components/avatar.dart index 47ca14b..c32faa9 100644 --- a/lib/components/avatar.dart +++ b/lib/components/avatar.dart @@ -1,5 +1,4 @@ import 'package:famedlysdk/famedlysdk.dart'; -import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/utils/string_color.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -28,31 +27,49 @@ class Avatar extends StatelessWidget { Matrix.of(context).client, width: size * MediaQuery.of(context).devicePixelRatio, height: size * MediaQuery.of(context).devicePixelRatio, - method: ThumbnailMethod.scale, ); final src = thumbnail; var fallbackLetters = '@'; if ((name?.length ?? 0) >= 2) { - fallbackLetters = name.substring(0, 2); + fallbackLetters = String.fromCharCodes(name.runes, 0, 2); } else if ((name?.length ?? 0) == 1) { fallbackLetters = name; } + final textWidget = Center( + child: Text( + fallbackLetters, + style: TextStyle( + color: Colors.white, + fontSize: 18, + ), + ), + ); final noPic = mxContent == null || mxContent.toString().isEmpty; return InkWell( onTap: onTap, - child: CircleAvatar( - radius: size / 2, - backgroundImage: !noPic - ? PlatformInfos.isBetaDesktop - ? NetworkImage(src) - : CachedNetworkImageProvider(src) - : null, - backgroundColor: noPic - ? name?.lightColor ?? Theme.of(context).secondaryHeaderColor - : Theme.of(context).secondaryHeaderColor, - child: noPic - ? Text(fallbackLetters, style: TextStyle(color: Colors.white)) - : null, + child: ClipRRect( + borderRadius: BorderRadius.circular(size / 2), + child: Container( + width: size, + height: size, + color: noPic + ? name?.lightColor ?? Theme.of(context).secondaryHeaderColor + : Theme.of(context).secondaryHeaderColor, + child: noPic + ? textWidget + : CachedNetworkImage( + imageUrl: src, + fit: BoxFit.cover, + width: size, + height: size, + placeholder: (c, s) => Stack( + children: [ + Center(child: CircularProgressIndicator(strokeWidth: 2)), + textWidget, + ], + ), + ), + ), ), ); } diff --git a/lib/components/content_banner.dart b/lib/components/content_banner.dart index 16292e0..40eefde 100644 --- a/lib/components/content_banner.dart +++ b/lib/components/content_banner.dart @@ -1,5 +1,4 @@ import 'package:famedlysdk/famedlysdk.dart'; -import 'package:fluffychat/utils/platform_infos.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:cached_network_image/cached_network_image.dart'; @@ -49,17 +48,11 @@ class ContentBanner extends StatelessWidget { opacity: 0.75, child: !loading ? mxContent != null - ? PlatformInfos.isBetaDesktop - ? Image.network( - src, - height: 300, - fit: BoxFit.cover, - ) - : CachedNetworkImage( - imageUrl: src, - height: 300, - fit: BoxFit.cover, - ) + ? CachedNetworkImage( + imageUrl: src, + height: 300, + fit: BoxFit.cover, + ) : Icon(defaultIcon, size: 300) : Icon(defaultIcon, size: 300), ), diff --git a/lib/components/image_bubble.dart b/lib/components/image_bubble.dart index 5d12bdd..8b23f77 100644 --- a/lib/components/image_bubble.dart +++ b/lib/components/image_bubble.dart @@ -1,6 +1,5 @@ import 'package:famedlysdk/famedlysdk.dart'; import 'package:fluffychat/utils/app_route.dart'; -import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/views/image_view.dart'; import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart'; @@ -127,17 +126,11 @@ class _ImageBubbleState extends State { width: 800, height: 800, method: ThumbnailMethod.scale); - renderWidget = PlatformInfos.isBetaDesktop - ? Image.network( - src, - fit: widget.fit, - ) - : CachedNetworkImage( - imageUrl: src, - placeholder: (context, url) => - generatePlaceholderWidget(), - fit: widget.fit, - ); + renderWidget = CachedNetworkImage( + imageUrl: src, + placeholder: (context, url) => generatePlaceholderWidget(), + fit: widget.fit, + ); } else { renderWidget = generatePlaceholderWidget(); } diff --git a/lib/components/input_bar.dart b/lib/components/input_bar.dart index 90e2cc2..7fe9b07 100644 --- a/lib/components/input_bar.dart +++ b/lib/components/input_bar.dart @@ -1,4 +1,3 @@ -import 'package:fluffychat/utils/platform_infos.dart'; import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart'; import 'package:famedlysdk/famedlysdk.dart'; @@ -149,17 +148,11 @@ class InputBar extends StatelessWidget { child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ - PlatformInfos.isBetaDesktop - ? Image.network( - url, - width: size, - height: size, - ) - : CachedNetworkImage( - imageUrl: url, - width: size, - height: size, - ), + CachedNetworkImage( + imageUrl: url, + width: size, + height: size, + ), SizedBox(width: 6), Text(suggestion['name']), Expanded( diff --git a/lib/components/matrix.dart b/lib/components/matrix.dart index 17b1fe4..f626e5e 100644 --- a/lib/components/matrix.dart +++ b/lib/components/matrix.dart @@ -13,6 +13,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:universal_html/prefer_universal/html.dart' as html; import 'package:url_launcher/url_launcher.dart'; +/*import 'package:fluffychat/views/chat.dart'; +import 'package:fluffychat/config/app_config.dart'; +import 'package:dbus/dbus.dart'; +import 'package:desktop_notifications/desktop_notifications.dart';*/ import '../main.dart'; import '../utils/app_route.dart'; @@ -179,9 +183,10 @@ class MatrixState extends State { bool webHasFocus = true; - void _showWebNotification(EventUpdate eventUpdate) async { - if (webHasFocus && activeRoomId == eventUpdate.roomID) return; - final room = client.getRoomById(eventUpdate.roomID); + void _showLocalNotification(EventUpdate eventUpdate) async { + final roomId = eventUpdate.roomID; + if (webHasFocus && activeRoomId == roomId) return; + final room = client.getRoomById(roomId); if (room.notificationCount == 0) return; final event = Event.fromJson(eventUpdate.content, room); final body = event.getLocalizedBody( @@ -189,20 +194,41 @@ class MatrixState extends State { withSenderNamePrefix: !room.isDirectChat || room.lastEvent.senderId == client.userID, ); - html.AudioElement() - ..src = 'assets/assets/sounds/notification.wav' - ..autoplay = true - ..load(); - html.Notification( - room.getLocalizedDisplayname(MatrixLocals(L10n.of(context))), - body: body, - icon: event.sender.avatarUrl?.getThumbnail(client, - width: 64, height: 64, method: ThumbnailMethod.crop) ?? - room.avatar?.getThumbnail(client, - width: 64, height: 64, method: ThumbnailMethod.crop), - ); + final icon = event.sender.avatarUrl?.getThumbnail(client, + width: 64, height: 64, method: ThumbnailMethod.crop) ?? + room.avatar?.getThumbnail(client, + width: 64, height: 64, method: ThumbnailMethod.crop); + if (kIsWeb) { + html.AudioElement() + ..src = 'assets/assets/sounds/notification.wav' + ..autoplay = true + ..load(); + html.Notification( + room.getLocalizedDisplayname(MatrixLocals(L10n.of(context))), + body: body, + icon: icon, + ); + } else if (Platform.isLinux) { + /*var sessionBus = DBusClient.session(); + var client = NotificationClient(sessionBus); + _linuxNotificationIds[roomId] = await client.notify( + room.getLocalizedDisplayname(MatrixLocals(L10n.of(context))), + body: body, + replacesID: _linuxNotificationIds[roomId] ?? -1, + appName: AppConfig.applicationName, + actionCallback: (_) => Navigator.of(context).pushAndRemoveUntil( + AppRoute.defaultRoute( + context, + ChatView(roomId), + ), + (r) => r.isFirst), + ); + await sessionBus.close();*/ + } } + //final Map _linuxNotificationIds = {}; + @override void initState() { store = widget.store ?? Store(); @@ -289,7 +315,8 @@ class MatrixState extends State { if (kIsWeb) { onFocusSub = html.window.onFocus.listen((_) => webHasFocus = true); onBlurSub = html.window.onBlur.listen((_) => webHasFocus = false); - + } + if (kIsWeb || Platform.isLinux) { client.onSync.stream.first.then((s) { html.Notification.requestPermission(); onNotification ??= client.onEvent.stream @@ -298,7 +325,7 @@ class MatrixState extends State { [EventTypes.Message, EventTypes.Sticker, EventTypes.Encrypted] .contains(e.eventType) && e.content['sender'] != client.userID) - .listen(_showWebNotification); + .listen(_showLocalNotification); }); } super.initState(); diff --git a/lib/components/message_reactions.dart b/lib/components/message_reactions.dart index cf09add..2619891 100644 --- a/lib/components/message_reactions.dart +++ b/lib/components/message_reactions.dart @@ -1,5 +1,4 @@ import 'package:famedlysdk/famedlysdk.dart'; -import 'package:fluffychat/utils/platform_infos.dart'; import 'package:flutter/material.dart'; import 'package:cached_network_image/cached_network_image.dart'; @@ -93,15 +92,10 @@ class _Reaction extends StatelessWidget { content = Row( mainAxisSize: MainAxisSize.min, children: [ - PlatformInfos.isBetaDesktop - ? Image.network( - src, - height: fontSize, - ) - : CachedNetworkImage( - imageUrl: src, - height: fontSize, - ), + CachedNetworkImage( + imageUrl: src, + height: fontSize, + ), Container(width: 4), Text(count.toString(), style: TextStyle( diff --git a/lib/views/settings_emotes.dart b/lib/views/settings_emotes.dart index 5046031..d7bca13 100644 --- a/lib/views/settings_emotes.dart +++ b/lib/views/settings_emotes.dart @@ -417,19 +417,12 @@ class _EmoteImage extends StatelessWidget { height: size * devicePixelRatio, method: ThumbnailMethod.scale, ); - return PlatformInfos.isBetaDesktop - ? Image.network( - url, - fit: BoxFit.contain, - width: size, - height: size, - ) - : CachedNetworkImage( - imageUrl: url, - fit: BoxFit.contain, - width: size, - height: size, - ); + return CachedNetworkImage( + imageUrl: url, + fit: BoxFit.contain, + width: size, + height: size, + ); } } diff --git a/pubspec.lock b/pubspec.lock index 66ae763..2765e48 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -77,7 +77,7 @@ packages: name: cached_network_image url: "https://pub.dartlang.org" source: hosted - version: "2.3.2+1" + version: "2.3.3" canonical_json: dependency: transitive description: @@ -287,7 +287,7 @@ packages: name: flutter_cache_manager url: "https://pub.dartlang.org" source: hosted - version: "1.4.2" + version: "2.0.0" flutter_keyboard_visibility: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index a2047ad..922e61e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -33,9 +33,10 @@ dependencies: file_picker_cross: ^4.2.2 image_picker: ^0.6.7+11 url_launcher: ^5.7.2 - cached_network_image: ^2.3.2+1 + cached_network_image: ^2.3.3 firebase_messaging: ^7.0.2 flutter_local_notifications: ^1.4.3 + # desktop_notifications: ^0.0.0-dev.4 // Currently blocked by: https://github.com/canonical/desktop_notifications.dart/issues/5 matrix_link_text: ^0.1.5 path_provider: ^1.5.1 webview_flutter: ^0.3.19+9