From 7e1e4e48448483834c6da8a55af5113509c3da4c Mon Sep 17 00:00:00 2001 From: Sorunome Date: Sat, 31 Jul 2021 12:31:31 +0200 Subject: [PATCH 1/3] feat: Rate limit streams so that large accounts have a smoother UI --- lib/pages/views/chat_list_view.dart | 4 +- lib/pages/views/chat_view.dart | 14 +++++-- lib/utils/stream_extension.dart | 46 ++++++++++++++++++++++ lib/widgets/list_items/chat_list_item.dart | 4 +- 4 files changed, 62 insertions(+), 6 deletions(-) create mode 100644 lib/utils/stream_extension.dart diff --git a/lib/pages/views/chat_list_view.dart b/lib/pages/views/chat_list_view.dart index 79db5c38..8d35cb75 100644 --- a/lib/pages/views/chat_list_view.dart +++ b/lib/pages/views/chat_list_view.dart @@ -9,6 +9,7 @@ import 'package:flutter/material.dart'; import 'package:vrouter/vrouter.dart'; import '../../widgets/matrix.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; +import '../../utils/stream_extension.dart'; class ChatListView extends StatelessWidget { final ChatListController controller; @@ -161,7 +162,8 @@ class ChatListView extends StatelessWidget { .client .onSync .stream - .where((s) => s.hasRoomUpdate), + .where((s) => s.hasRoomUpdate) + .rateLimit(Duration(seconds: 1)), builder: (context, snapshot) { return FutureBuilder( future: controller.waitForFirstSync(), diff --git a/lib/pages/views/chat_view.dart b/lib/pages/views/chat_view.dart index fc2260f7..e60f8e2d 100644 --- a/lib/pages/views/chat_view.dart +++ b/lib/pages/views/chat_view.dart @@ -27,6 +27,8 @@ import 'package:scroll_to_index/scroll_to_index.dart'; import 'package:swipe_to_action/swipe_to_action.dart'; import 'package:vrouter/vrouter.dart'; +import '../../utils/stream_extension.dart'; + class ChatView extends StatelessWidget { final ChatController controller; @@ -72,7 +74,8 @@ class ChatView extends StatelessWidget { titleSpacing: 0, title: controller.selectedEvents.isEmpty ? StreamBuilder( - stream: controller.room.onUpdate.stream, + stream: controller.room.onUpdate.stream + .rateLimit(Duration(milliseconds: 250)), builder: (context, snapshot) => ListTile( leading: Avatar(controller.room.avatar, controller.room.displayname), @@ -105,7 +108,8 @@ class ChatView extends StatelessWidget { .stream .where((p) => p.senderId == - controller.room.directChatMatrixID), + controller.room.directChatMatrixID) + .rateLimit(Duration(seconds: 1)), builder: (context, snapshot) => Text( controller.room .getLocalizedStatus(context), @@ -283,8 +287,10 @@ class ChatView extends StatelessWidget { : Container() : i == 0 ? StreamBuilder( - stream: - controller.room.onUpdate.stream, + stream: controller + .room.onUpdate.stream + .rateLimit(Duration( + milliseconds: 250)), builder: (_, __) { final seenByText = controller.room .getLocalizedSeenByText( diff --git a/lib/utils/stream_extension.dart b/lib/utils/stream_extension.dart new file mode 100644 index 00000000..e7b739da --- /dev/null +++ b/lib/utils/stream_extension.dart @@ -0,0 +1,46 @@ +import 'dart:async'; + +extension StreamExtension on Stream { + /// Returns a new Stream which outputs only `true` for every update of the original + /// stream, ratelimited by the Duration t + Stream rateLimit(Duration t) { + final controller = StreamController(); + Timer timer; + var gotMessage = false; + // as we call our inline-defined function recursively we need to make sure that the + // variable exists prior of creating the function. Silly dart. + Function _onMessage; + // callback to determine if we should send out an update + _onMessage = () { + // do nothing if it is already closed + if (controller.isClosed) { + return; + } + if (timer == null) { + // if we don't have a timer yet, send out the update and start a timer + gotMessage = false; + controller.add(true); + timer = Timer(t, () { + // the timer has ended...delete it and, if we got a message, re-run the + // method to send out an update! + timer = null; + if (gotMessage) { + _onMessage(); + } + }); + } else { + // set that we got a message + gotMessage = true; + } + }; + final subscription = listen((_) => _onMessage(), + onDone: () => controller.close(), + onError: (e, s) => controller.addError(e, s)); + // add proper cleanup to the subscription and the controller, to not memory leak + controller.onCancel = () { + subscription.cancel(); + controller.close(); + }; + return controller.stream; + } +} diff --git a/lib/widgets/list_items/chat_list_item.dart b/lib/widgets/list_items/chat_list_item.dart index 93bb6387..c0a48889 100644 --- a/lib/widgets/list_items/chat_list_item.dart +++ b/lib/widgets/list_items/chat_list_item.dart @@ -289,7 +289,9 @@ class ChatListItem extends StatelessWidget { curve: Curves.bounceInOut, padding: EdgeInsets.symmetric(horizontal: 7), height: unreadBubbleSize, - width: room.notificationCount == 0 && !room.isUnread ? 0 : null, + width: room.notificationCount == 0 && !room.isUnread + ? 0 + : unreadBubbleSize, decoration: BoxDecoration( color: room.highlightCount > 0 ? Colors.red From f10130ed05d886b0865c8957b368ece5ed9780ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A1ja=20Li=C5=A1kov=C3=A1?= Date: Sat, 31 Jul 2021 07:04:08 -0500 Subject: [PATCH 2/3] Fix app title capitalisation --- ios/Runner/Info.plist | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 67f085cc..6f699bc1 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -8,6 +8,8 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + FluffyChat CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -19,7 +21,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - $(MARKETING_VERSION) + $(FLUTTER_BUILD_NAME) CFBundleSignature ???? CFBundleURLTypes @@ -38,8 +40,6 @@ CFBundleVersion $(FLUTTER_BUILD_NUMBER) - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) LSRequiresIPhoneOS NSAppleMusicUsageDescription From 05e62ddcb66eaf1bec8b497ce72b2ab337ae8c7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A1ja=20Li=C5=A1kov=C3=A1?= Date: Sat, 31 Jul 2021 07:16:44 -0500 Subject: [PATCH 3/3] Fix capitalisation for macOS app --- macos/Runner.xcodeproj/project.pbxproj | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index 0782d54a..ac87b51b 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -56,7 +56,7 @@ 2D20EFA3D49BBBDA1F07645D /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* fluffychat.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = fluffychat.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10ED2044A3C60003C045 /* FluffyChat.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FluffyChat.app; sourceTree = BUILT_PRODUCTS_DIR; }; 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; @@ -112,7 +112,7 @@ 33CC10EE2044A3C60003C045 /* Products */ = { isa = PBXGroup; children = ( - 33CC10ED2044A3C60003C045 /* fluffychat.app */, + 33CC10ED2044A3C60003C045 /* FluffyChat.app */, ); name = Products; sourceTree = ""; @@ -192,7 +192,7 @@ ); name = Runner; productName = Runner; - productReference = 33CC10ED2044A3C60003C045 /* fluffychat.app */; + productReference = 33CC10ED2044A3C60003C045 /* FluffyChat.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ @@ -461,6 +461,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); + PRODUCT_NAME = FluffyChat; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; @@ -592,6 +593,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); + PRODUCT_NAME = FluffyChat; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -617,6 +619,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); + PRODUCT_NAME = FluffyChat; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; };