mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 18:08:40 +00:00
fix #89
This commit is contained in:
parent
bf34920350
commit
cb595004e4
5 changed files with 115 additions and 79 deletions
|
|
@ -144,6 +144,10 @@ class MessagesDao extends DatabaseAccessor<TwonlyDatabase>
|
||||||
return (delete(messages)..where((t) => t.messageId.equals(messageId))).go();
|
return (delete(messages)..where((t) => t.messageId.equals(messageId))).go();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future deleteMessagesByContactId(int contactId) {
|
||||||
|
return (delete(messages)..where((t) => t.contactId.equals(contactId))).go();
|
||||||
|
}
|
||||||
|
|
||||||
Future<bool> containsOtherMessageId(
|
Future<bool> containsOtherMessageId(
|
||||||
int fromUserId, int messageOtherId) async {
|
int fromUserId, int messageOtherId) async {
|
||||||
final query = select(messages)
|
final query = select(messages)
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,8 @@
|
||||||
"contactNickname": "Spitzname",
|
"contactNickname": "Spitzname",
|
||||||
"contactNicknameNew": "Neuer Spitzname",
|
"contactNicknameNew": "Neuer Spitzname",
|
||||||
"contactBlock": "Blockieren",
|
"contactBlock": "Blockieren",
|
||||||
|
"deleteAllContactMessages": "Alle Nachrichten löschen",
|
||||||
|
"deleteAllContactMessagesBody": "Dadurch werden alle Nachrichten in deinem Chat mit {username} gelöscht. Dies löscht NICHT die auf dem Gerät von {username} gespeicherten Nachrichten!",
|
||||||
"contactBlockTitle": "Blockiere {username}",
|
"contactBlockTitle": "Blockiere {username}",
|
||||||
"contactBlockBody": "Ein blockierter Benutzer kann dir keine Nachrichten mehr senden, und sein Profil ist nicht mehr sichtbar. Um die Blockierung eines Benutzers aufzuheben, navigiere einfach zu Einstellungen > Datenschutz > Blockierte Benutzer.",
|
"contactBlockBody": "Ein blockierter Benutzer kann dir keine Nachrichten mehr senden, und sein Profil ist nicht mehr sichtbar. Um die Blockierung eines Benutzers aufzuheben, navigiere einfach zu Einstellungen > Datenschutz > Blockierte Benutzer.",
|
||||||
"undo": "Rückgängig",
|
"undo": "Rückgängig",
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,8 @@
|
||||||
"contactVerifyNumberLongDesc": "To verify the end-to-end encryption with {username}, compare the numbers with their device. The person can also scan your code with their device.",
|
"contactVerifyNumberLongDesc": "To verify the end-to-end encryption with {username}, compare the numbers with their device. The person can also scan your code with their device.",
|
||||||
"contactNickname": "Nickname",
|
"contactNickname": "Nickname",
|
||||||
"contactNicknameNew": "New nickname",
|
"contactNicknameNew": "New nickname",
|
||||||
|
"deleteAllContactMessages": "Delete all messages",
|
||||||
|
"deleteAllContactMessagesBody": "This will remove all messages in your chat with {username}. This will NOT delete the messages stored at {username}s device!",
|
||||||
"contactBlock": "Block",
|
"contactBlock": "Block",
|
||||||
"contactBlockTitle": "Block {username}",
|
"contactBlockTitle": "Block {username}",
|
||||||
"contactBlockBody": "A blocked user will no longer be able to send you messages and their profile will be hidden from view. To unblock a user, simply navigate to Settings > Privacy > Blocked Users.",
|
"contactBlockBody": "A blocked user will no longer be able to send you messages and their profile will be hidden from view. To unblock a user, simply navigate to Settings > Privacy > Blocked Users.",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:twonly/globals.dart';
|
import 'package:twonly/globals.dart';
|
||||||
|
|
@ -121,6 +120,7 @@ class _ChatListViewState extends State<ChatListView> {
|
||||||
|
|
||||||
return RefreshIndicator(
|
return RefreshIndicator(
|
||||||
onRefresh: () async {
|
onRefresh: () async {
|
||||||
|
await apiProvider.close(() {});
|
||||||
await apiProvider.connect();
|
await apiProvider.connect();
|
||||||
await Future.delayed(Duration(seconds: 1));
|
await Future.delayed(Duration(seconds: 1));
|
||||||
},
|
},
|
||||||
|
|
@ -130,6 +130,7 @@ class _ChatListViewState extends State<ChatListView> {
|
||||||
itemBuilder: (BuildContext context, int index) {
|
itemBuilder: (BuildContext context, int index) {
|
||||||
final user = contacts[index];
|
final user = contacts[index];
|
||||||
return UserListItem(
|
return UserListItem(
|
||||||
|
key: ValueKey(user.userId),
|
||||||
user: user,
|
user: user,
|
||||||
maxTotalMediaCounter: maxTotalMediaCounter,
|
maxTotalMediaCounter: maxTotalMediaCounter,
|
||||||
);
|
);
|
||||||
|
|
@ -158,14 +159,80 @@ class _UserListItem extends State<UserListItem> {
|
||||||
MessageSendState state = MessageSendState.send;
|
MessageSendState state = MessageSendState.send;
|
||||||
Message? currentMessage;
|
Message? currentMessage;
|
||||||
|
|
||||||
|
List<Message> messagesNotOpened = [];
|
||||||
|
late StreamSubscription<List<Message>> messagesNotOpenedStream;
|
||||||
|
|
||||||
|
List<Message> lastMessages = [];
|
||||||
|
late StreamSubscription<List<Message>> lastMessageStream;
|
||||||
|
|
||||||
Timer? updateTime;
|
Timer? updateTime;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
initStreams();
|
||||||
lastUpdateTime();
|
lastUpdateTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void initStreams() {
|
||||||
|
lastMessageStream = twonlyDatabase.messagesDao
|
||||||
|
.watchLastMessage(widget.user.userId)
|
||||||
|
.listen((update) {
|
||||||
|
updateState(update, messagesNotOpened);
|
||||||
|
});
|
||||||
|
|
||||||
|
messagesNotOpenedStream = twonlyDatabase.messagesDao
|
||||||
|
.watchMessageNotOpened(widget.user.userId)
|
||||||
|
.listen((update) {
|
||||||
|
updateState(lastMessages, update);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateState(
|
||||||
|
List<Message> newLastMessages,
|
||||||
|
List<Message> newMessagesNotOpened,
|
||||||
|
) {
|
||||||
|
if (newLastMessages.isEmpty) {
|
||||||
|
// there are no messages at all
|
||||||
|
currentMessage = null;
|
||||||
|
} else if (newMessagesNotOpened.isEmpty) {
|
||||||
|
// there are no not opened messages show just the last message in the table
|
||||||
|
currentMessage = newLastMessages.first;
|
||||||
|
} else {
|
||||||
|
// filter first for received messages
|
||||||
|
final receivedMessages =
|
||||||
|
newMessagesNotOpened.where((x) => x.messageOtherId != null).toList();
|
||||||
|
|
||||||
|
if (receivedMessages.isNotEmpty) {
|
||||||
|
// There are received messages
|
||||||
|
final mediaMessages =
|
||||||
|
receivedMessages.where((x) => x.kind == MessageKind.media);
|
||||||
|
|
||||||
|
if (mediaMessages.isNotEmpty) {
|
||||||
|
currentMessage = mediaMessages.first;
|
||||||
|
} else {
|
||||||
|
currentMessage = receivedMessages.first;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// The not opened message was send
|
||||||
|
final mediaMessages =
|
||||||
|
newMessagesNotOpened.where((x) => x.kind == MessageKind.media);
|
||||||
|
|
||||||
|
if (mediaMessages.isNotEmpty) {
|
||||||
|
currentMessage = mediaMessages.first;
|
||||||
|
} else {
|
||||||
|
currentMessage = newMessagesNotOpened.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastMessages = newLastMessages;
|
||||||
|
messagesNotOpened = newMessagesNotOpened;
|
||||||
|
setState(() {
|
||||||
|
// sets lastMessages, messagesNotOpened and currentMessage
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void lastUpdateTime() {
|
void lastUpdateTime() {
|
||||||
// Change the color every 200 milliseconds
|
// Change the color every 200 milliseconds
|
||||||
updateTime = Timer.periodic(Duration(milliseconds: 200), (timer) {
|
updateTime = Timer.periodic(Duration(milliseconds: 200), (timer) {
|
||||||
|
|
@ -185,6 +252,8 @@ class _UserListItem extends State<UserListItem> {
|
||||||
void dispose() {
|
void dispose() {
|
||||||
updateTime?.cancel();
|
updateTime?.cancel();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
|
messagesNotOpenedStream.cancel();
|
||||||
|
lastMessageStream.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -195,64 +264,9 @@ class _UserListItem extends State<UserListItem> {
|
||||||
contact: widget.user,
|
contact: widget.user,
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
title: Text(getContactDisplayName(widget.user)),
|
title: Text(getContactDisplayName(widget.user)),
|
||||||
subtitle: StreamBuilder(
|
subtitle: (currentMessage == null)
|
||||||
stream:
|
? Text(context.lang.chatsTapToSend)
|
||||||
twonlyDatabase.messagesDao.watchLastMessage(widget.user.userId),
|
: Row(
|
||||||
builder: (context, lastMessageSnapshot) {
|
|
||||||
if (!lastMessageSnapshot.hasData) {
|
|
||||||
return Container();
|
|
||||||
}
|
|
||||||
if (lastMessageSnapshot.data!.isEmpty) {
|
|
||||||
return Text(context.lang.chatsTapToSend);
|
|
||||||
}
|
|
||||||
final lastMessage = lastMessageSnapshot.data!.first;
|
|
||||||
return StreamBuilder(
|
|
||||||
stream: twonlyDatabase.messagesDao
|
|
||||||
.watchMessageNotOpened(widget.user.userId),
|
|
||||||
builder: (context, notOpenedMessagesSnapshot) {
|
|
||||||
if (!lastMessageSnapshot.hasData) {
|
|
||||||
return Container();
|
|
||||||
}
|
|
||||||
|
|
||||||
var lastMessages = [lastMessage];
|
|
||||||
if (notOpenedMessagesSnapshot.data != null &&
|
|
||||||
notOpenedMessagesSnapshot.data!.isNotEmpty) {
|
|
||||||
// filter first for only received messages
|
|
||||||
var notOpenedMessages = notOpenedMessagesSnapshot.data!;
|
|
||||||
|
|
||||||
lastMessages = notOpenedMessages
|
|
||||||
.where((x) => x.messageOtherId != null)
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
// For send images show only one
|
|
||||||
if (lastMessages.isEmpty) {
|
|
||||||
var media = notOpenedMessages
|
|
||||||
.where((x) => x.kind == MessageKind.media);
|
|
||||||
|
|
||||||
if (media.isNotEmpty) {
|
|
||||||
currentMessage = media.first;
|
|
||||||
lastMessages = [currentMessage!];
|
|
||||||
} else {
|
|
||||||
currentMessage = notOpenedMessages.first;
|
|
||||||
lastMessages = [currentMessage!];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// there are multiple messages received
|
|
||||||
|
|
||||||
var media =
|
|
||||||
lastMessages.where((x) => x.kind == MessageKind.media);
|
|
||||||
|
|
||||||
if (media.isNotEmpty) {
|
|
||||||
currentMessage = media.first;
|
|
||||||
} else {
|
|
||||||
currentMessage = lastMessages.first;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
currentMessage = lastMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Row(
|
|
||||||
children: [
|
children: [
|
||||||
MessageSendStateIcon(lastMessages),
|
MessageSendStateIcon(lastMessages),
|
||||||
Text("•"),
|
Text("•"),
|
||||||
|
|
@ -269,10 +283,6 @@ class _UserListItem extends State<UserListItem> {
|
||||||
prefix: true,
|
prefix: true,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
leading: ContactAvatar(contact: widget.user),
|
leading: ContactAvatar(contact: widget.user),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,24 @@ class _ContactViewState extends State<ContactView> {
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
BetterListTile(
|
||||||
|
icon: FontAwesomeIcons.trashCan,
|
||||||
|
text: context.lang.deleteAllContactMessages,
|
||||||
|
onTap: () async {
|
||||||
|
bool block = await showAlertDialog(
|
||||||
|
context,
|
||||||
|
context.lang.deleteAllContactMessages,
|
||||||
|
context.lang.deleteAllContactMessagesBody(
|
||||||
|
getContactDisplayName(contact)),
|
||||||
|
);
|
||||||
|
if (block) {
|
||||||
|
if (context.mounted) {
|
||||||
|
await twonlyDatabase.messagesDao
|
||||||
|
.deleteMessagesByContactId(contact.userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
BetterListTile(
|
BetterListTile(
|
||||||
icon: FontAwesomeIcons.ban,
|
icon: FontAwesomeIcons.ban,
|
||||||
color: Colors.red,
|
color: Colors.red,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue