mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-05-25 02:12:13 +00:00
fix: messages where opene even if the app is in the background
This commit is contained in:
parent
5b5140ec7c
commit
a93187c86d
3 changed files with 60 additions and 29 deletions
|
|
@ -161,18 +161,6 @@ class MessagesDao extends DatabaseAccessor<TwonlyDB> with _$MessagesDaoMixin {
|
|||
}
|
||||
}
|
||||
|
||||
Future<void> openedAllTextMessages(String groupId) {
|
||||
final updates = MessagesCompanion(openedAt: Value(clock.now()));
|
||||
return (update(messages)..where(
|
||||
(t) =>
|
||||
t.groupId.equals(groupId) &
|
||||
t.senderId.isNotNull() &
|
||||
t.openedAt.isNull() &
|
||||
t.type.equals(MessageType.text.name),
|
||||
))
|
||||
.write(updates);
|
||||
}
|
||||
|
||||
Future<void> handleMessageDeletion(
|
||||
int? contactId,
|
||||
String messageId,
|
||||
|
|
@ -184,13 +172,13 @@ class MessagesDao extends DatabaseAccessor<TwonlyDB> with _$MessagesDaoMixin {
|
|||
return;
|
||||
}
|
||||
if (msg.mediaId != null && contactId != null) {
|
||||
final otherMessagesWithSameMedia = await (select(messages)
|
||||
..where(
|
||||
(t) =>
|
||||
t.mediaId.equals(msg.mediaId!) &
|
||||
t.messageId.equals(messageId).not(),
|
||||
))
|
||||
.get();
|
||||
final otherMessagesWithSameMedia =
|
||||
await (select(messages)..where(
|
||||
(t) =>
|
||||
t.mediaId.equals(msg.mediaId!) &
|
||||
t.messageId.equals(messageId).not(),
|
||||
))
|
||||
.get();
|
||||
|
||||
if (otherMessagesWithSameMedia.isEmpty) {
|
||||
await (delete(
|
||||
|
|
@ -210,7 +198,7 @@ class MessagesDao extends DatabaseAccessor<TwonlyDB> with _$MessagesDaoMixin {
|
|||
await (delete(
|
||||
messageHistories,
|
||||
)..where((t) => t.messageId.equals(messageId))).go();
|
||||
|
||||
|
||||
await twonlyDB.receiptsDao.deleteReceiptsByMessageId(messageId);
|
||||
|
||||
await (update(messages)..where(
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
|||
import 'package:go_router/go_router.dart';
|
||||
import 'package:mutex/mutex.dart';
|
||||
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
||||
import 'package:twonly/globals.dart';
|
||||
import 'package:twonly/locator.dart';
|
||||
import 'package:twonly/src/constants/routes.keys.dart';
|
||||
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
||||
|
|
@ -36,7 +37,7 @@ class ChatMessagesView extends StatefulWidget {
|
|||
State<ChatMessagesView> createState() => _ChatMessagesViewState();
|
||||
}
|
||||
|
||||
class _ChatMessagesViewState extends State<ChatMessagesView> {
|
||||
class _ChatMessagesViewState extends State<ChatMessagesView> with WidgetsBindingObserver {
|
||||
HashSet<int> alreadyReportedOpened = HashSet<int>();
|
||||
late StreamSubscription<Group?> userSub;
|
||||
late StreamSubscription<List<Message>> messageSub;
|
||||
|
|
@ -64,6 +65,7 @@ class _ChatMessagesViewState extends State<ChatMessagesView> {
|
|||
void initState() {
|
||||
super.initState();
|
||||
textFieldFocus = FocusNode();
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
initStreams();
|
||||
}
|
||||
|
||||
|
|
@ -74,11 +76,26 @@ class _ChatMessagesViewState extends State<ChatMessagesView> {
|
|||
contactSub?.cancel();
|
||||
groupActionsSub?.cancel();
|
||||
_nextTypingIndicator?.cancel();
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Mutex protectMessageUpdating = Mutex();
|
||||
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
if (state == AppLifecycleState.resumed) {
|
||||
protectMessageUpdating.protect(() async {
|
||||
await setMessages(allMessages, groupActions);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bool _isViewActive() {
|
||||
return !AppState.isAppInBackground &&
|
||||
(ModalRoute.of(context)?.isCurrent ?? false);
|
||||
}
|
||||
|
||||
Future<void> initStreams() async {
|
||||
final groupStream = twonlyDB.groupsDao.watchGroup(widget.groupId);
|
||||
userSub = groupStream.listen((newGroup) {
|
||||
|
|
@ -137,7 +154,9 @@ class _ChatMessagesViewState extends State<ChatMessagesView> {
|
|||
List<Message> newMessages,
|
||||
List<GroupHistory> groupActions,
|
||||
) async {
|
||||
await flutterLocalNotificationsPlugin.cancelAll();
|
||||
if (_isViewActive()) {
|
||||
await flutterLocalNotificationsPlugin.cancelAll();
|
||||
}
|
||||
|
||||
final chatItems = <ChatItem>[];
|
||||
final storedMediaFiles = <Message>[];
|
||||
|
|
@ -189,11 +208,13 @@ class _ChatMessagesViewState extends State<ChatMessagesView> {
|
|||
}
|
||||
}
|
||||
|
||||
for (final contactId in openedMessages.keys) {
|
||||
await notifyContactAboutOpeningMessage(
|
||||
contactId,
|
||||
openedMessages[contactId]!,
|
||||
);
|
||||
if (_isViewActive()) {
|
||||
for (final contactId in openedMessages.keys) {
|
||||
await notifyContactAboutOpeningMessage(
|
||||
contactId,
|
||||
openedMessages[contactId]!,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!mounted) return;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import 'package:lottie/lottie.dart';
|
|||
import 'package:mutex/mutex.dart';
|
||||
import 'package:no_screenshot/no_screenshot.dart';
|
||||
import 'package:photo_view/photo_view.dart';
|
||||
import 'package:twonly/globals.dart';
|
||||
import 'package:twonly/locator.dart';
|
||||
import 'package:twonly/src/constants/routes.keys.dart';
|
||||
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
||||
|
|
@ -46,7 +47,8 @@ class MediaViewerView extends StatefulWidget {
|
|||
State<MediaViewerView> createState() => _MediaViewerViewState();
|
||||
}
|
||||
|
||||
class _MediaViewerViewState extends State<MediaViewerView> {
|
||||
class _MediaViewerViewState extends State<MediaViewerView>
|
||||
with WidgetsBindingObserver {
|
||||
Timer? nextMediaTimer;
|
||||
Timer? progressTimer;
|
||||
|
||||
|
|
@ -87,6 +89,7 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
|||
if (widget.initialMessage != null) {
|
||||
allMediaFiles = [widget.initialMessage!];
|
||||
}
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
|
||||
asyncLoadNextMedia(true);
|
||||
}
|
||||
|
|
@ -101,11 +104,28 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
|||
final tmp = videoController;
|
||||
videoController = null;
|
||||
tmp?.dispose();
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
final Mutex _messageUpdateLock = Mutex();
|
||||
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
if (state == AppLifecycleState.resumed) {
|
||||
_messageUpdateLock.protect(() async {
|
||||
if (currentMedia == null && allMediaFiles.isNotEmpty) {
|
||||
await loadCurrentMediaFile();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bool _isViewActive() {
|
||||
return !AppState.isAppInBackground &&
|
||||
(ModalRoute.of(context)?.isCurrent ?? false);
|
||||
}
|
||||
|
||||
Future<void> asyncLoadNextMedia(bool firstRun) async {
|
||||
_subscription = twonlyDB.messagesDao
|
||||
.watchMediaNotOpened(widget.group.groupId)
|
||||
|
|
@ -195,7 +215,9 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
|||
showSendTextMessageInput = false;
|
||||
});
|
||||
|
||||
unawaited(flutterLocalNotificationsPlugin.cancelAll());
|
||||
if (_isViewActive()) {
|
||||
unawaited(flutterLocalNotificationsPlugin.cancelAll());
|
||||
}
|
||||
|
||||
final stream = twonlyDB.mediaFilesDao.watchMedia(
|
||||
allMediaFiles.first.mediaId!,
|
||||
|
|
|
|||
Loading…
Reference in a new issue