From ce60f4e2f1187ed2def42dfca53f8299de074370 Mon Sep 17 00:00:00 2001 From: otsmr Date: Sun, 26 Apr 2026 02:38:01 +0200 Subject: [PATCH] smaller improvements --- lib/src/services/api/messages.api.dart | 2 +- .../feedback_btn.comp.dart | 46 +- .../views/chats/chat_messages.view.dart | 2 +- .../typing_indicator.dart | 2 +- .../visual/views/chats/media_viewer.view.dart | 409 +++++++++--------- .../protocols/src/user_discovery.rs | 2 +- 6 files changed, 221 insertions(+), 242 deletions(-) diff --git a/lib/src/services/api/messages.api.dart b/lib/src/services/api/messages.api.dart index fbd5b43a..7cce2ffe 100644 --- a/lib/src/services/api/messages.api.dart +++ b/lib/src/services/api/messages.api.dart @@ -341,7 +341,7 @@ Future<(Uint8List, Uint8List?)?> sendCipherText( final openReceipts = await twonlyDB.receiptsDao.getReceiptCountForContact( contactId, ); - if (openReceipts > 2) { + if (openReceipts > 6) { // this prevents that these types of messages are send in case the receiver is offline return null; } diff --git a/lib/src/visual/views/chats/chat_list_components/feedback_btn.comp.dart b/lib/src/visual/views/chats/chat_list_components/feedback_btn.comp.dart index 63bfd309..498af280 100644 --- a/lib/src/visual/views/chats/chat_list_components/feedback_btn.comp.dart +++ b/lib/src/visual/views/chats/chat_list_components/feedback_btn.comp.dart @@ -1,5 +1,3 @@ -import 'dart:async'; - import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:go_router/go_router.dart'; @@ -7,40 +5,24 @@ import 'package:twonly/locator.dart'; import 'package:twonly/src/constants/routes.keys.dart'; import 'package:twonly/src/utils/misc.dart'; -class FeedbackIconButtonComp extends StatefulWidget { +class FeedbackIconButtonComp extends StatelessWidget { const FeedbackIconButtonComp({super.key}); - @override - State createState() => _FeedbackIconButtonCompState(); -} - -class _FeedbackIconButtonCompState extends State { - bool showFeedbackShortcut = false; - - @override - void initState() { - super.initState(); - unawaited(initAsync()); - } - - Future initAsync() async { - if (!mounted) return; - setState(() { - showFeedbackShortcut = userService.currentUser.showFeedbackShortcut; - }); - } - @override Widget build(BuildContext context) { - if (!showFeedbackShortcut) { - return const SizedBox.shrink(); - } - - return IconButton( - onPressed: () => context.push(Routes.settingsHelpContactUs), - color: Colors.grey, - tooltip: context.lang.feedbackTooltip, - icon: const FaIcon(FontAwesomeIcons.commentDots, size: 19), + return StreamBuilder( + stream: userService.onUserUpdated, + builder: (context, asyncSnapshot) { + if (!userService.currentUser.showFeedbackShortcut) { + return const SizedBox.shrink(); + } + return IconButton( + onPressed: () => context.push(Routes.settingsHelpContactUs), + color: Colors.grey, + tooltip: context.lang.feedbackTooltip, + icon: const FaIcon(FontAwesomeIcons.commentDots, size: 19), + ); + }, ); } } diff --git a/lib/src/visual/views/chats/chat_messages.view.dart b/lib/src/visual/views/chats/chat_messages.view.dart index 49ba1b7b..ab1e59d2 100644 --- a/lib/src/visual/views/chats/chat_messages.view.dart +++ b/lib/src/visual/views/chats/chat_messages.view.dart @@ -125,7 +125,7 @@ class _ChatMessagesViewState extends State { if (userService.currentUser.typingIndicators) { unawaited(sendTypingIndication(widget.groupId, false)); - _nextTypingIndicator = Timer.periodic(const Duration(seconds: 4), ( + _nextTypingIndicator = Timer.periodic(const Duration(seconds: 2), ( _, ) async { await sendTypingIndication(widget.groupId, false); diff --git a/lib/src/visual/views/chats/chat_messages_components/typing_indicator.dart b/lib/src/visual/views/chats/chat_messages_components/typing_indicator.dart index 92c53bd0..804974b2 100644 --- a/lib/src/visual/views/chats/chat_messages_components/typing_indicator.dart +++ b/lib/src/visual/views/chats/chat_messages_components/typing_indicator.dart @@ -28,7 +28,7 @@ bool hasChatOpen(GroupMember member) { member.lastChatOpened!, ) .inSeconds <= - 6; + 3; } class TypingIndicator extends StatefulWidget { diff --git a/lib/src/visual/views/chats/media_viewer.view.dart b/lib/src/visual/views/chats/media_viewer.view.dart index 46ef723d..dcb200f6 100644 --- a/lib/src/visual/views/chats/media_viewer.view.dart +++ b/lib/src/visual/views/chats/media_viewer.view.dart @@ -546,218 +546,215 @@ class _MediaViewerViewState extends State { @override Widget build(BuildContext context) { return Scaffold( - body: SafeArea( - child: Stack( - fit: StackFit.expand, - children: [ - if (_showDownloadingLoader) _loader(), - if ((currentMedia != null || videoController != null) && - (canBeSeenUntil == null || progress >= 0)) - GestureDetector( - onTap: () { - if (showSendTextMessageInput) { - setState(() { - showShortReactions = false; - showSendTextMessageInput = false; - }); - return; - } - nextMediaOrExit(); - }, - child: MediaViewSizingHelper( - bottomNavigation: bottomNavigation(), - requiredHeight: 55, - child: Stack( - children: [ - if (videoController != null) - Positioned.fill( - child: PhotoView.customChild( - initialScale: PhotoViewComputedScale.contained, - minScale: PhotoViewComputedScale.contained, - child: VideoPlayer(videoController!), - ), - ) - else if (currentMedia != null && - currentMedia!.mediaFile.type == MediaType.image || - currentMedia!.mediaFile.type == MediaType.gif) - Positioned.fill( - child: PhotoView( - imageProvider: FileImage( - currentMedia!.tempPath, - ), - initialScale: PhotoViewComputedScale.contained, - minScale: PhotoViewComputedScale.contained, - ), - ), - ], - ), - ), - ), - if (displayTwonlyPresent) - Positioned.fill( - child: GestureDetector( - onTap: () => loadCurrentMediaFile(showTwonly: true), - child: Column( - children: [ - Expanded( - child: Lottie.asset( - 'assets/animations/present.lottie.lottie', - ), - ), - Container( - padding: const EdgeInsets.only(bottom: 200), - child: Text(context.lang.mediaViewerTwonlyTapToOpen), - ), - ], - ), - ), - ), - Positioned( - left: 10, - top: 10, - child: Row( - children: [ - IconButton( - icon: const Icon(Icons.close, size: 30), - color: Colors.white, - onPressed: () => Navigator.pop(context), - ), - ], - ), - ), - if (currentMedia != null && - currentMedia?.mediaFile.downloadState != DownloadState.ready) - Positioned.fill(child: _loader()), - if (canBeSeenUntil != null || progress >= 0) - Positioned( - right: 20, - top: 27, - child: Row( - children: [ - SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator( - value: progress, - strokeWidth: 2, - ), - ), - ], - ), - ), - Positioned( - top: 10, - left: showSendTextMessageInput ? 0 : null, - right: showSendTextMessageInput ? 0 : 15, - child: Text( - _currentMediaSender, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: showSendTextMessageInput ? 24 : 14, - fontWeight: FontWeight.bold, - color: showSendTextMessageInput - ? null - : const Color.fromARGB(255, 126, 126, 126), - shadows: const [ - Shadow( - color: Color.fromARGB(122, 0, 0, 0), - blurRadius: 5, - ), - ], - ), - ), - ), - if (showSendTextMessageInput) - Positioned( - bottom: 0, - left: 0, - right: 0, - child: Container( - color: context.color.surface, - padding: const EdgeInsets.only( - bottom: 10, - left: 20, - right: 20, - top: 10, - ), - child: Row( - children: [ - IconButton( - icon: const FaIcon(FontAwesomeIcons.xmark), - onPressed: () { - setState(() { - showShortReactions = false; - showSendTextMessageInput = false; - }); - }, - ), - Expanded( - child: TextField( - autofocus: true, - controller: textMessageController, - onChanged: (value) async { - await twonlyDB.groupsDao.updateGroup( - widget.group.groupId, - GroupsCompanion( - draftMessage: Value(textMessageController.text), - ), - ); - }, - onEditingComplete: () { - setState(() { - showSendTextMessageInput = false; - showShortReactions = false; - }); - }, - decoration: inputTextMessageDeco( - context, - context.lang.chatListDetailInput, - ), - ), - ), - IconButton( - icon: const FaIcon(FontAwesomeIcons.solidPaperPlane), - onPressed: () async { - if (textMessageController.text.isNotEmpty) { - await insertAndSendTextMessage( - widget.group.groupId, - textMessageController.text, - currentMessage!.messageId, - ); - textMessageController.clear(); - } - setState(() { - showSendTextMessageInput = false; - showShortReactions = false; - }); - }, - ), - ], - ), - ), - ), - if (currentMessage != null) - AdditionalMessageContent(currentMessage!), - if (currentMedia != null) - ReactionButtons( - show: showShortReactions, - textInputFocused: showSendTextMessageInput, - mediaViewerDistanceFromBottom: mediaViewerDistanceFromBottom, - groupId: widget.group.groupId, - messageId: currentMessage!.messageId, - emojiKey: emojiKey, - hide: () { + body: Stack( + fit: StackFit.expand, + children: [ + if (_showDownloadingLoader) _loader(), + if ((currentMedia != null || videoController != null) && + (canBeSeenUntil == null || progress >= 0)) + GestureDetector( + onTap: () { + if (showSendTextMessageInput) { setState(() { showShortReactions = false; showSendTextMessageInput = false; }); - }, + return; + } + nextMediaOrExit(); + }, + child: MediaViewSizingHelper( + bottomNavigation: bottomNavigation(), + requiredHeight: 55, + child: Stack( + children: [ + if (videoController != null) + Positioned.fill( + child: PhotoView.customChild( + initialScale: PhotoViewComputedScale.contained, + minScale: PhotoViewComputedScale.contained, + child: VideoPlayer(videoController!), + ), + ) + else if (currentMedia != null && + currentMedia!.mediaFile.type == MediaType.image || + currentMedia!.mediaFile.type == MediaType.gif) + Positioned.fill( + child: PhotoView( + imageProvider: FileImage( + currentMedia!.tempPath, + ), + initialScale: PhotoViewComputedScale.contained, + minScale: PhotoViewComputedScale.contained, + ), + ), + ], + ), ), - Positioned.fill( - child: EmojiFloatWidget(key: emojiKey), ), - ], - ), + if (displayTwonlyPresent) + Positioned.fill( + child: GestureDetector( + onTap: () => loadCurrentMediaFile(showTwonly: true), + child: Column( + children: [ + Expanded( + child: Lottie.asset( + 'assets/animations/present.lottie.lottie', + ), + ), + Container( + padding: const EdgeInsets.only(bottom: 200), + child: Text(context.lang.mediaViewerTwonlyTapToOpen), + ), + ], + ), + ), + ), + Positioned( + left: 10, + top: 10, + child: Row( + children: [ + IconButton( + icon: const Icon(Icons.close, size: 30), + color: Colors.white, + onPressed: () => Navigator.pop(context), + ), + ], + ), + ), + if (currentMedia != null && + currentMedia?.mediaFile.downloadState != DownloadState.ready) + Positioned.fill(child: _loader()), + if (canBeSeenUntil != null || progress >= 0) + Positioned( + right: 20, + top: 27, + child: Row( + children: [ + SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + value: progress, + strokeWidth: 2, + ), + ), + ], + ), + ), + Positioned( + top: 10, + left: showSendTextMessageInput ? 0 : null, + right: showSendTextMessageInput ? 0 : 15, + child: Text( + _currentMediaSender, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: showSendTextMessageInput ? 24 : 14, + fontWeight: FontWeight.bold, + color: showSendTextMessageInput + ? null + : const Color.fromARGB(255, 126, 126, 126), + shadows: const [ + Shadow( + color: Color.fromARGB(122, 0, 0, 0), + blurRadius: 5, + ), + ], + ), + ), + ), + if (showSendTextMessageInput) + Positioned( + bottom: 0, + left: 0, + right: 0, + child: Container( + color: context.color.surface, + padding: const EdgeInsets.only( + bottom: 10, + left: 20, + right: 20, + top: 10, + ), + child: Row( + children: [ + IconButton( + icon: const FaIcon(FontAwesomeIcons.xmark), + onPressed: () { + setState(() { + showShortReactions = false; + showSendTextMessageInput = false; + }); + }, + ), + Expanded( + child: TextField( + autofocus: true, + controller: textMessageController, + onChanged: (value) async { + await twonlyDB.groupsDao.updateGroup( + widget.group.groupId, + GroupsCompanion( + draftMessage: Value(textMessageController.text), + ), + ); + }, + onEditingComplete: () { + setState(() { + showSendTextMessageInput = false; + showShortReactions = false; + }); + }, + decoration: inputTextMessageDeco( + context, + context.lang.chatListDetailInput, + ), + ), + ), + IconButton( + icon: const FaIcon(FontAwesomeIcons.solidPaperPlane), + onPressed: () async { + if (textMessageController.text.isNotEmpty) { + await insertAndSendTextMessage( + widget.group.groupId, + textMessageController.text, + currentMessage!.messageId, + ); + textMessageController.clear(); + } + setState(() { + showSendTextMessageInput = false; + showShortReactions = false; + }); + }, + ), + ], + ), + ), + ), + if (currentMessage != null) AdditionalMessageContent(currentMessage!), + if (currentMedia != null) + ReactionButtons( + show: showShortReactions, + textInputFocused: showSendTextMessageInput, + mediaViewerDistanceFromBottom: mediaViewerDistanceFromBottom, + groupId: widget.group.groupId, + messageId: currentMessage!.messageId, + emojiKey: emojiKey, + hide: () { + setState(() { + showShortReactions = false; + showSendTextMessageInput = false; + }); + }, + ), + Positioned.fill( + child: EmojiFloatWidget(key: emojiKey), + ), + ], ), ); } diff --git a/rust_dependencies/protocols/src/user_discovery.rs b/rust_dependencies/protocols/src/user_discovery.rs index e90db9d8..b6bf2978 100644 --- a/rust_dependencies/protocols/src/user_discovery.rs +++ b/rust_dependencies/protocols/src/user_discovery.rs @@ -221,7 +221,7 @@ impl UserDiscovery