diff --git a/lib/chat/cubits/chat_component_cubit.dart b/lib/chat/cubits/chat_component_cubit.dart index a1c64bf..737b1a4 100644 --- a/lib/chat/cubits/chat_component_cubit.dart +++ b/lib/chat/cubits/chat_component_cubit.dart @@ -333,6 +333,7 @@ class ChatComponentCubit extends Cubit { text: contentText.text, metadata: { kSeqId: message.seqId, + kSending: message.sendState == MessageSendState.sending, if (core.isOnlyEmoji(contentText.text)) 'isOnlyEmoji': true, }); return (currentState, textMessage); diff --git a/lib/chat/cubits/single_contact_messages_cubit.dart b/lib/chat/cubits/single_contact_messages_cubit.dart index d93c4be..77b1bb9 100644 --- a/lib/chat/cubits/single_contact_messages_cubit.dart +++ b/lib/chat/cubits/single_contact_messages_cubit.dart @@ -419,22 +419,22 @@ class SingleContactMessagesCubit extends Cubit { } // Render in-flight messages at the bottom - // - // for (final m in unsentMessages) { - // if (renderedIds.contains(m.authorUniqueIdString)) { - // seqId++; - // continue; - // } - // renderedElements.add(RenderStateElement( - // seqId: seqId, - // message: m, - // isLocal: true, - // sent: true, - // sentOffline: true, - // )); - // renderedIds.add(m.authorUniqueIdString); - // seqId++; - // } + + for (final m in unsentMessages) { + if (renderedIds.contains(m.authorUniqueIdString)) { + seqId++; + continue; + } + renderedElements.add(RenderStateElement( + seqId: seqId, + message: m, + isLocal: true, + sent: true, + sentOffline: true, + )); + renderedIds.add(m.authorUniqueIdString); + seqId++; + } // Render the state final messages = renderedElements diff --git a/lib/chat/views/chat_component_widget.dart b/lib/chat/views/chat_component_widget.dart index aed7356..5ecf6e9 100644 --- a/lib/chat/views/chat_component_widget.dart +++ b/lib/chat/views/chat_component_widget.dart @@ -23,6 +23,7 @@ import 'chat_builders/chat_builders.dart'; const onEndReachedThreshold = 0.75; const _kScrollTag = 'kScrollTag'; const kSeqId = 'seqId'; +const kSending = 'sending'; const maxMessageLength = 2048; class ChatComponentWidget extends StatefulWidget { @@ -321,51 +322,55 @@ class _ChatComponentWidgetState extends State { final windowState = data.value; - await _chatController.setMessages(windowState.window.toList()); + // await _chatController.setMessages(windowState.window.toList()); - // final newMessagesSet = windowState.window.toSet(); - // final newMessagesById = - // Map.fromEntries(newMessagesSet.map((m) => MapEntry(m.id, m))); - // final newMessagesBySeqId = Map.fromEntries( - // newMessagesSet.map((m) => MapEntry(m.metadata![kSeqId], m))); - // final oldMessagesSet = _chatController.messages.toSet(); + final newMessagesSet = windowState.window.toSet(); + final newMessagesById = + Map.fromEntries(newMessagesSet.map((m) => MapEntry(m.id, m))); + final newMessagesBySeqId = Map.fromEntries( + newMessagesSet.map((m) => MapEntry(m.metadata![kSeqId], m))); + final oldMessagesSet = _chatController.messages.toSet(); - // if (oldMessagesSet.isEmpty) { - // await _chatController.setMessages(windowState.window.toList()); - // return; - // } + if (oldMessagesSet.isEmpty) { + await _chatController.setMessages(windowState.window.toList()); + return; + } - // // See how many messages differ by equality (not identity) - // // If there are more than `replaceAllMessagesThreshold` differences - // // just replace the whole list of messages - // final diffs = newMessagesSet.diffAndIntersect(oldMessagesSet, - // diffThisMinusOther: true, diffOtherMinusThis: true); - // final addedMessages = diffs.diffThisMinusOther!; - // final removedMessages = diffs.diffOtherMinusThis!; + // See how many messages differ by equality (not identity) + // If there are more than `replaceAllMessagesThreshold` differences + // just replace the whole list of messages + final diffs = newMessagesSet.diffAndIntersect(oldMessagesSet, + diffThisMinusOther: true, diffOtherMinusThis: true); + final addedMessages = diffs.diffThisMinusOther!; + final removedMessages = diffs.diffOtherMinusThis!; - // final replaceAllPaginationLimit = windowState.windowCount / 3; + final replaceAllPaginationLimit = windowState.windowCount / 3; - // if ((addedMessages.length >= replaceAllPaginationLimit) || - // removedMessages.length >= replaceAllPaginationLimit) { - // await _chatController.setMessages(windowState.window.toList()); - // return; - // } + if ((addedMessages.length >= replaceAllPaginationLimit) || + removedMessages.length >= replaceAllPaginationLimit) { + await _chatController.setMessages(windowState.window.toList()); + return; + } - // // Remove messages that are gone, and replace the ones that have changed - // for (final m in removedMessages) { - // final newm = newMessagesById[m.id]; - // if (newm != null) { - // await _chatController.updateMessage(m, newm); - // } else { - // final newm = newMessagesBySeqId[m.metadata![kSeqId]]; - // if (newm != null) { - // await _chatController.updateMessage(m, newm); - // addedMessages.remove(newm); - // } else { - // await _chatController.removeMessage(m); - // } - // } - // } + // Remove messages that are gone, and replace the ones that have changed + for (final m in removedMessages) { + final newm = newMessagesById[m.id]; + if (newm != null) { + await _chatController.updateMessage(m, newm); + } else { + final newm = newMessagesBySeqId[m.metadata![kSeqId]]; + if (newm != null) { + await _chatController.updateMessage(m, newm); + addedMessages.remove(newm); + } else { + await _chatController.removeMessage(m); + } + } + } + + if (addedMessages.isNotEmpty) { + await _chatController.setMessages(windowState.window.toList()); + } // // // Check for append // if (addedMessages.isNotEmpty) { diff --git a/lib/keyboard_shortcuts.dart b/lib/keyboard_shortcuts.dart index 1e25dac..6708d72 100644 --- a/lib/keyboard_shortcuts.dart +++ b/lib/keyboard_shortcuts.dart @@ -125,27 +125,32 @@ class KeyboardShortcuts extends StatelessWidget { @override Widget build(BuildContext context) => ThemeSwitcher( builder: (context) => Shortcuts( - shortcuts: { - LogicalKeySet( - LogicalKeyboardKey.alt, - LogicalKeyboardKey.control, - LogicalKeyboardKey.keyR): const ReloadThemeIntent(), - LogicalKeySet( - LogicalKeyboardKey.alt, - LogicalKeyboardKey.control, - LogicalKeyboardKey.keyB): const ChangeBrightnessIntent(), - LogicalKeySet( - LogicalKeyboardKey.alt, - LogicalKeyboardKey.control, - LogicalKeyboardKey.keyC): const ChangeColorIntent(), - LogicalKeySet( - LogicalKeyboardKey.alt, - LogicalKeyboardKey.control, - LogicalKeyboardKey.keyD): const AttachDetachIntent(), - LogicalKeySet( - LogicalKeyboardKey.alt, - LogicalKeyboardKey.control, - LogicalKeyboardKey.backquote): const DeveloperPageIntent(), + shortcuts: const { + SingleActivator( + LogicalKeyboardKey.keyR, + control: true, + alt: true, + ): ReloadThemeIntent(), + SingleActivator( + LogicalKeyboardKey.keyB, + control: true, + alt: true, + ): ChangeBrightnessIntent(), + SingleActivator( + LogicalKeyboardKey.keyC, + control: true, + alt: true, + ): ChangeColorIntent(), + SingleActivator( + LogicalKeyboardKey.keyA, + control: true, + alt: true, + ): AttachDetachIntent(), + SingleActivator( + LogicalKeyboardKey.keyD, + control: true, + alt: true, + ): DeveloperPageIntent(), }, child: Actions(actions: >{ ReloadThemeIntent: CallbackAction( diff --git a/pubspec.lock b/pubspec.lock index 47990cf..cdec931 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: dc27559385e905ad30838356c5f5d574014ba39872d732111cd07ac0beff4c57 + sha256: e55636ed79578b9abca5fecf9437947798f5ef7456308b5cb85720b793eac92f url: "https://pub.dev" source: hosted - version: "80.0.0" + version: "82.0.0" accordion: dependency: "direct main" description: @@ -21,10 +21,10 @@ packages: dependency: transitive description: name: analyzer - sha256: "192d1c5b944e7e53b24b5586db760db934b177d4147c42fbca8c8c5f1eb8d11e" + sha256: "904ae5bb474d32c38fb9482e2d925d5454cda04ddd0e55d2e6826bc72f6ba8c0" url: "https://pub.dev" source: hosted - version: "7.3.0" + version: "7.4.5" animated_bottom_navigation_bar: dependency: "direct main" description: @@ -69,10 +69,10 @@ packages: dependency: "direct main" description: name: archive - sha256: "0c64e928dcbefddecd234205422bcfc2b5e6d31be0b86fef0d0dd48d7b4c9742" + sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd" url: "https://pub.dev" source: hosted - version: "4.0.4" + version: "4.0.7" args: dependency: transitive description: @@ -141,10 +141,10 @@ packages: dependency: transitive description: name: bidi - sha256: "9a712c7ddf708f7c41b1923aa83648a3ed44cfd75b04f72d598c45e5be287f9d" + sha256: "77f475165e94b261745cf1032c751e2032b8ed92ccb2bf5716036db79320637d" url: "https://pub.dev" source: hosted - version: "2.0.12" + version: "2.0.13" bloc: dependency: "direct main" description: @@ -277,26 +277,26 @@ packages: dependency: transitive description: name: camera_android_camerax - sha256: "13784f539c7f104766bff84e4479a70f03b29d78b208278be45c939250d9d7f5" + sha256: ea7e40bd63afb8f55058e48ec529ce96562be9d08393f79631a06f781161fd0d url: "https://pub.dev" source: hosted - version: "0.6.14+1" + version: "0.6.16" camera_avfoundation: dependency: transitive description: name: camera_avfoundation - sha256: ba48b65a3a97004276ede882e6b838d9667642ff462c95a8bb57ca8a82b6bd25 + sha256: ca36181194f429eef3b09de3c96280f2400693f9735025f90d1f4a27465fdd72 url: "https://pub.dev" source: hosted - version: "0.9.18+11" + version: "0.9.19" camera_platform_interface: dependency: transitive description: name: camera_platform_interface - sha256: "953e7baed3a7c8fae92f7200afeb2be503ff1a17c3b4e4ed7b76f008c2810a31" + sha256: "2f757024a48696ff4814a789b0bd90f5660c0fb25f393ab4564fb483327930e2" url: "https://pub.dev" source: hosted - version: "2.9.0" + version: "2.10.0" camera_web: dependency: transitive description: @@ -485,10 +485,10 @@ packages: dependency: "direct main" description: name: fast_immutable_collections - sha256: "95a69b9380483dff49ae2c12c9eb92e2b4e1aeff481a33c2a20883471771598a" + sha256: d1aa3d7788fab06cce7f303f4969c7a16a10c865e1bd2478291a8ebcbee084e5 url: "https://pub.dev" source: hosted - version: "11.0.3" + version: "11.0.4" ffi: dependency: transitive description: @@ -538,10 +538,10 @@ packages: dependency: "direct main" description: name: flutter_bloc - sha256: "1046d719fbdf230330d3443187cc33cc11963d15c9089f6cc56faa42a4c5f0cc" + sha256: cf51747952201a455a1c840f8171d273be009b932c75093020f9af64f2123e38 url: "https://pub.dev" source: hosted - version: "9.1.0" + version: "9.1.1" flutter_cache_manager: dependency: transitive description: @@ -591,18 +591,18 @@ packages: dependency: "direct main" description: name: flutter_native_splash - sha256: edb09c35ee9230c4b03f13dd45bb3a276d0801865f0a4650b7e2a3bba61a803a + sha256: "8321a6d11a8d13977fa780c89de8d257cce3d841eecfb7a4cadffcc4f12d82dc" url: "https://pub.dev" source: hosted - version: "2.4.5" + version: "2.4.6" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "5a1e6fb2c0561958d7e4c33574674bda7b77caaca7a33b758876956f2902eea3" + sha256: f948e346c12f8d5480d2825e03de228d0eb8c3a737e4cdaa122267b89c022b5e url: "https://pub.dev" source: hosted - version: "2.0.27" + version: "2.0.28" flutter_shaders: dependency: transitive description: @@ -639,10 +639,10 @@ packages: dependency: "direct main" description: name: flutter_svg - sha256: c200fd79c918a40c5cd50ea0877fa13f81bdaf6f0a5d3dbcc2a13e3285d6aa1b + sha256: d44bf546b13025ec7353091516f6881f1d4c633993cb109c3916c3a0159dadf1 url: "https://pub.dev" source: hosted - version: "2.0.17" + version: "2.1.0" flutter_translate: dependency: "direct main" description: @@ -676,10 +676,10 @@ packages: dependency: "direct dev" description: name: freezed - sha256: "7ed2ddaa47524976d5f2aa91432a79da36a76969edd84170777ac5bea82d797c" + sha256: "6022db4c7bfa626841b2a10f34dd1e1b68e8f8f9650db6112dcdeeca45ca793c" url: "https://pub.dev" source: hosted - version: "3.0.4" + version: "3.0.6" freezed_annotation: dependency: "direct main" description: @@ -740,18 +740,18 @@ packages: dependency: transitive description: name: html - sha256: "1fc58edeaec4307368c60d59b7e15b9d658b57d7f3125098b6294153c75337ec" + sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602" url: "https://pub.dev" source: hosted - version: "0.15.5" + version: "0.15.6" http: dependency: transitive description: name: http - sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f + sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" http_multi_server: dependency: transitive description: @@ -796,10 +796,10 @@ packages: dependency: "direct main" description: name: image - sha256: "13d3349ace88f12f4a0d175eb5c12dcdd39d35c4c109a8a13dfeb6d0bd9e31c3" + sha256: "4e973fcf4caae1a4be2fa0a13157aa38a8f9cb049db6529aa00b4d71abc4d928" url: "https://pub.dev" source: hosted - version: "4.5.3" + version: "4.5.4" indent: dependency: transitive description: @@ -844,10 +844,10 @@ packages: dependency: "direct dev" description: name: json_serializable - sha256: "81f04dee10969f89f604e1249382d46b97a1ccad53872875369622b5bfc9e58a" + sha256: c50ef5fc083d5b5e12eef489503ba3bf5ccc899e487d691584699b4bdefeea8c url: "https://pub.dev" source: hosted - version: "6.9.4" + version: "6.9.5" keyboard_avoider: dependency: "direct main" description: @@ -860,10 +860,10 @@ packages: dependency: "direct dev" description: name: lint_hard - sha256: ffe7058cb49e021d244d67e650a63380445b56643c2849c6929e938246b99058 + sha256: "2073d4e83ac4e3f2b87cc615fff41abb5c2c5618e117edcd3d71f40f2186f4d5" url: "https://pub.dev" source: hosted - version: "6.0.0" + version: "6.1.1" logging: dependency: transitive description: @@ -916,10 +916,10 @@ packages: dependency: "direct main" description: name: mobile_scanner - sha256: "9cb9e371ee9b5b548714f9ab5fd33b530d799745c83d5729ecd1e8ab2935dbd1" + sha256: f536c5b8cadcf73d764bdce09c94744f06aa832264730f8971b21a60c5666826 url: "https://pub.dev" source: hosted - version: "6.0.7" + version: "6.0.10" nested: dependency: transitive description: @@ -996,10 +996,10 @@ packages: dependency: transitive description: name: path_provider_android - sha256: "0ca7359dad67fd7063cb2892ab0c0737b2daafd807cf1acecd62374c8fae6c12" + sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9 url: "https://pub.dev" source: hosted - version: "2.2.16" + version: "2.2.17" path_provider_foundation: dependency: transitive description: @@ -1108,10 +1108,10 @@ packages: dependency: transitive description: name: posix - sha256: a0117dc2167805aa9125b82eee515cc891819bac2f538c83646d355b16f58b9a + sha256: f0d7856b6ca1887cfa6d1d394056a296ae33489db914e365e2044fdada449e62 url: "https://pub.dev" source: hosted - version: "6.0.1" + version: "6.0.2" preload_page_view: dependency: "direct main" description: @@ -1292,10 +1292,10 @@ packages: dependency: transitive description: name: scrollview_observer - sha256: "437c930927c5a3240ed2d40398f99d96eaca58f861817ff44f6d0c60113bcf9d" + sha256: "174d4efe7b79459a07662175c4db42c9862dcf78d3978e6e9c2d6c0d8137f4ca" url: "https://pub.dev" source: hosted - version: "1.26.0" + version: "1.26.1" searchable_listview: dependency: "direct main" description: @@ -1333,18 +1333,18 @@ packages: dependency: "direct main" description: name: shared_preferences - sha256: "846849e3e9b68f3ef4b60c60cf4b3e02e9321bc7f4d8c4692cf87ffa82fc8a3a" + sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5" url: "https://pub.dev" source: hosted - version: "2.5.2" + version: "2.5.3" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "3ec7210872c4ba945e3244982918e502fa2bfb5230dff6832459ca0e1879b7ad" + sha256: "20cbd561f743a342c76c151d6ddb93a9ce6005751e7aa458baad3858bfbfb6ac" url: "https://pub.dev" source: hosted - version: "2.4.8" + version: "2.4.10" shared_preferences_foundation: dependency: transitive description: @@ -1603,10 +1603,10 @@ packages: dependency: transitive description: name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + sha256: "6c7653816b1c938e121b69ff63a33c9dc68102b65a5fb0a5c0f9786256ed33e6" url: "https://pub.dev" source: hosted - version: "0.7.4" + version: "0.7.5" timing: dependency: transitive description: @@ -1667,18 +1667,18 @@ packages: dependency: transitive description: name: url_launcher_android - sha256: "1d0eae19bd7606ef60fe69ef3b312a437a16549476c42321d5dc1506c9ca3bf4" + sha256: "8582d7f6fe14d2652b4c45c9b6c14c0b678c2af2d083a11b604caeba51930d79" url: "https://pub.dev" source: hosted - version: "6.3.15" + version: "6.3.16" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: "16a513b6c12bb419304e72ea0ae2ab4fed569920d1c7cb850263fe3acc824626" + sha256: "7f2022359d4c099eea7df3fdf739f7d3d3b9faf3166fb1dd390775176e0b76cb" url: "https://pub.dev" source: hosted - version: "6.3.2" + version: "6.3.3" url_launcher_linux: dependency: transitive description: @@ -1707,10 +1707,10 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: "3ba963161bd0fe395917ba881d320b9c4f6dd3c4a233da62ab18a5025c85f1e9" + sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" url_launcher_windows: dependency: transitive description: @@ -1801,26 +1801,26 @@ packages: dependency: transitive description: name: web_socket - sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" + sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" url: "https://pub.dev" source: hosted - version: "0.1.6" + version: "1.0.1" web_socket_channel: dependency: transitive description: name: web_socket_channel - sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5" + sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.3" win32: dependency: transitive description: name: win32 - sha256: dc6ecaa00a7c708e5b4d10ee7bec8c270e9276dfcab1783f57e9962d7884305f + sha256: "329edf97fdd893e0f1e3b9e88d6a0e627128cc17cc316a8d67fda8f1451178ba" url: "https://pub.dev" source: hosted - version: "5.12.0" + version: "5.13.0" window_manager: dependency: "direct main" description: