smaller improvements

This commit is contained in:
otsmr 2026-04-26 02:38:01 +02:00
parent dcca2cbec0
commit ce60f4e2f1
6 changed files with 221 additions and 242 deletions

View file

@ -341,7 +341,7 @@ Future<(Uint8List, Uint8List?)?> sendCipherText(
final openReceipts = await twonlyDB.receiptsDao.getReceiptCountForContact( final openReceipts = await twonlyDB.receiptsDao.getReceiptCountForContact(
contactId, contactId,
); );
if (openReceipts > 2) { if (openReceipts > 6) {
// this prevents that these types of messages are send in case the receiver is offline // this prevents that these types of messages are send in case the receiver is offline
return null; return null;
} }

View file

@ -1,5 +1,3 @@
import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.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/constants/routes.keys.dart';
import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/misc.dart';
class FeedbackIconButtonComp extends StatefulWidget { class FeedbackIconButtonComp extends StatelessWidget {
const FeedbackIconButtonComp({super.key}); const FeedbackIconButtonComp({super.key});
@override
State<FeedbackIconButtonComp> createState() => _FeedbackIconButtonCompState();
}
class _FeedbackIconButtonCompState extends State<FeedbackIconButtonComp> {
bool showFeedbackShortcut = false;
@override
void initState() {
super.initState();
unawaited(initAsync());
}
Future<void> initAsync() async {
if (!mounted) return;
setState(() {
showFeedbackShortcut = userService.currentUser.showFeedbackShortcut;
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (!showFeedbackShortcut) { return StreamBuilder(
return const SizedBox.shrink(); stream: userService.onUserUpdated,
} builder: (context, asyncSnapshot) {
if (!userService.currentUser.showFeedbackShortcut) {
return IconButton( return const SizedBox.shrink();
onPressed: () => context.push(Routes.settingsHelpContactUs), }
color: Colors.grey, return IconButton(
tooltip: context.lang.feedbackTooltip, onPressed: () => context.push(Routes.settingsHelpContactUs),
icon: const FaIcon(FontAwesomeIcons.commentDots, size: 19), color: Colors.grey,
tooltip: context.lang.feedbackTooltip,
icon: const FaIcon(FontAwesomeIcons.commentDots, size: 19),
);
},
); );
} }
} }

View file

@ -125,7 +125,7 @@ class _ChatMessagesViewState extends State<ChatMessagesView> {
if (userService.currentUser.typingIndicators) { if (userService.currentUser.typingIndicators) {
unawaited(sendTypingIndication(widget.groupId, false)); unawaited(sendTypingIndication(widget.groupId, false));
_nextTypingIndicator = Timer.periodic(const Duration(seconds: 4), ( _nextTypingIndicator = Timer.periodic(const Duration(seconds: 2), (
_, _,
) async { ) async {
await sendTypingIndication(widget.groupId, false); await sendTypingIndication(widget.groupId, false);

View file

@ -28,7 +28,7 @@ bool hasChatOpen(GroupMember member) {
member.lastChatOpened!, member.lastChatOpened!,
) )
.inSeconds <= .inSeconds <=
6; 3;
} }
class TypingIndicator extends StatefulWidget { class TypingIndicator extends StatefulWidget {

View file

@ -546,218 +546,215 @@ class _MediaViewerViewState extends State<MediaViewerView> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
body: SafeArea( body: Stack(
child: Stack( fit: StackFit.expand,
fit: StackFit.expand, children: [
children: [ if (_showDownloadingLoader) _loader(),
if (_showDownloadingLoader) _loader(), if ((currentMedia != null || videoController != null) &&
if ((currentMedia != null || videoController != null) && (canBeSeenUntil == null || progress >= 0))
(canBeSeenUntil == null || progress >= 0)) GestureDetector(
GestureDetector( onTap: () {
onTap: () { if (showSendTextMessageInput) {
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: () {
setState(() { setState(() {
showShortReactions = false; showShortReactions = false;
showSendTextMessageInput = 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),
),
],
), ),
); );
} }

View file

@ -221,7 +221,7 @@ impl<Store: UserDiscoveryStore, Utils: UserDiscoveryUtils> UserDiscovery<Store,
.get_own_promotions_after_version(received_version.promotion) .get_own_promotions_after_version(received_version.promotion)
.await? .await?
.into_iter() .into_iter()
.filter(|x| x.is_empty()) // filter ignored versions .filter(|x| !x.is_empty()) // filter ignored versions
.collect(); .collect();
messages.extend_from_slice(&promoting_messages); messages.extend_from_slice(&promoting_messages);
} }