mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 16:48:41 +00:00
hide users from search user name view
This commit is contained in:
parent
db8e4d4419
commit
42330594bb
8 changed files with 206 additions and 159 deletions
|
|
@ -56,7 +56,7 @@ class _UserContextMenuState extends State<UserContextMenu> {
|
|||
onSelect: () {
|
||||
Navigator.push(context, MaterialPageRoute(
|
||||
builder: (context) {
|
||||
return ChatItemDetailsView(widget.contact.userId);
|
||||
return ChatItemDetailsView(widget.contact);
|
||||
},
|
||||
));
|
||||
},
|
||||
|
|
|
|||
|
|
@ -108,7 +108,9 @@ class ContactsDao extends DatabaseAccessor<TwonlyDatabase>
|
|||
}
|
||||
|
||||
Stream<List<Contact>> watchNotAcceptedContacts() {
|
||||
return (select(contacts)..where((t) => t.accepted.equals(false))).watch();
|
||||
return (select(contacts)
|
||||
..where((t) => t.accepted.equals(false) & t.archived.equals(false)))
|
||||
.watch();
|
||||
// return (select(contacts)).watch();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,14 @@
|
|||
"searchUsernameNotFoundBody": "Es wurde kein Benutzer mit dem Benutzernamen \"{username}\" gefunden.",
|
||||
"searchUsernameNewFollowerTitle": "Folgeanfragen",
|
||||
"searchUsernameQrCodeBtn": "QR-Code scannen",
|
||||
"searchUserNamePending": "Ausstehend",
|
||||
"@searchUserNamePending": {},
|
||||
"searchUserNameBlockUserTooltip": "Benutzer ohne Benachrichtigung blockieren.",
|
||||
"@searchUserNameBlockUserTooltip": {},
|
||||
"searchUserNameRejectUserTooltip": "Die Anfrage ablehnen und den Anfragenden informieren.",
|
||||
"@searchUserNameRejectUserTooltip": {},
|
||||
"searchUserNameArchiveUserTooltip": "Benutzer archivieren. Du wirst informiert sobald er deine Anfrage akzeptiert.",
|
||||
"@searchUserNameArchiveUserTooltip": {},
|
||||
"chatListViewSearchUserNameBtn": "Füge deinen ersten twonly-Kontakt hinzu!",
|
||||
"chatListViewSendFirstTwonly": "Sende dein erstes twonly!",
|
||||
"chatListDetailInput": "Nachricht eingeben",
|
||||
|
|
|
|||
|
|
@ -68,6 +68,14 @@
|
|||
"@searchUsernameInput": {},
|
||||
"searchUsernameTitle": "Search username",
|
||||
"@searchUsernameTitle": {},
|
||||
"searchUserNamePending": "Pending",
|
||||
"@searchUserNamePending": {},
|
||||
"searchUserNameBlockUserTooltip": "Block the user without informing.",
|
||||
"@searchUserNameBlockUserTooltip": {},
|
||||
"searchUserNameRejectUserTooltip": "Reject the request and let the requester know.",
|
||||
"@searchUserNameRejectUserTooltip": {},
|
||||
"searchUserNameArchiveUserTooltip": "Archive the user. He will appear again as soon as he accepts your request.",
|
||||
"@searchUserNameArchiveUserTooltip": {},
|
||||
"searchUsernameNotFound": "Username not found",
|
||||
"@searchUsernameNotFound": {},
|
||||
"searchUsernameNotFoundBody": "There is no user with the username \"{username}\" registered",
|
||||
|
|
|
|||
|
|
@ -209,9 +209,9 @@ class ChatListEntry extends StatelessWidget {
|
|||
|
||||
/// Displays detailed information about a SampleItem.
|
||||
class ChatItemDetailsView extends StatefulWidget {
|
||||
const ChatItemDetailsView(this.userid, {super.key});
|
||||
const ChatItemDetailsView(this.contact, {super.key});
|
||||
|
||||
final int userid;
|
||||
final Contact contact;
|
||||
|
||||
@override
|
||||
State<ChatItemDetailsView> createState() => _ChatItemDetailsViewState();
|
||||
|
|
@ -220,7 +220,7 @@ class ChatItemDetailsView extends StatefulWidget {
|
|||
class _ChatItemDetailsViewState extends State<ChatItemDetailsView> {
|
||||
TextEditingController newMessageController = TextEditingController();
|
||||
HashSet<int> alreadyReportedOpened = HashSet<int>();
|
||||
Contact? user;
|
||||
late Contact user;
|
||||
String currentInputText = "";
|
||||
late StreamSubscription<Contact> userSub;
|
||||
late StreamSubscription<List<Message>> messageSub;
|
||||
|
|
@ -231,6 +231,7 @@ class _ChatItemDetailsViewState extends State<ChatItemDetailsView> {
|
|||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
user = widget.contact;
|
||||
initStreams();
|
||||
}
|
||||
|
||||
|
|
@ -244,7 +245,7 @@ class _ChatItemDetailsViewState extends State<ChatItemDetailsView> {
|
|||
Future initStreams() async {
|
||||
await twonlyDatabase.messagesDao.removeOldMessages();
|
||||
Stream<Contact> contact =
|
||||
twonlyDatabase.contactsDao.watchContact(widget.userid);
|
||||
twonlyDatabase.contactsDao.watchContact(widget.contact.userId);
|
||||
userSub = contact.listen((contact) {
|
||||
setState(() {
|
||||
user = contact;
|
||||
|
|
@ -252,15 +253,14 @@ class _ChatItemDetailsViewState extends State<ChatItemDetailsView> {
|
|||
});
|
||||
|
||||
Stream<List<Message>> msgStream =
|
||||
twonlyDatabase.messagesDao.watchAllMessagesFrom(widget.userid);
|
||||
twonlyDatabase.messagesDao.watchAllMessagesFrom(widget.contact.userId);
|
||||
messageSub = msgStream.listen((msgs) {
|
||||
if (!context.mounted) return;
|
||||
if (Platform.isAndroid) {
|
||||
flutterLocalNotificationsPlugin.cancel(widget.userid);
|
||||
flutterLocalNotificationsPlugin.cancel(widget.contact.userId);
|
||||
} else {
|
||||
flutterLocalNotificationsPlugin.cancelAll();
|
||||
}
|
||||
var updated = false;
|
||||
List<Message> displayedMessages = [];
|
||||
// should be cleared
|
||||
Map<int, List<Message>> tmpReactionsToMyMessages = {};
|
||||
|
|
@ -271,7 +271,6 @@ class _ChatItemDetailsViewState extends State<ChatItemDetailsView> {
|
|||
if (msg.kind == MessageKind.textMessage &&
|
||||
msg.messageOtherId != null &&
|
||||
msg.openedAt == null) {
|
||||
updated = true;
|
||||
openedMessageOtherIds.add(msg.messageOtherId!);
|
||||
}
|
||||
|
||||
|
|
@ -294,25 +293,27 @@ class _ChatItemDetailsViewState extends State<ChatItemDetailsView> {
|
|||
}
|
||||
}
|
||||
if (openedMessageOtherIds.isNotEmpty) {
|
||||
notifyContactAboutOpeningMessage(widget.userid, openedMessageOtherIds);
|
||||
notifyContactAboutOpeningMessage(
|
||||
widget.contact.userId, openedMessageOtherIds);
|
||||
}
|
||||
twonlyDatabase.messagesDao.openedAllNonMediaMessages(widget.userid);
|
||||
twonlyDatabase.messagesDao
|
||||
.openedAllNonMediaMessages(widget.contact.userId);
|
||||
// should be fixed with that
|
||||
if (!updated) {
|
||||
// The stream should be get an update, so only update the UI when all are opened
|
||||
setState(() {
|
||||
reactionsToMyMessages = tmpReactionsToMyMessages;
|
||||
reactionsToOtherMessages = tmpTeactionsToOtherMessages;
|
||||
messages = displayedMessages;
|
||||
});
|
||||
}
|
||||
// if (!updated) {
|
||||
// // The stream should be get an update, so only update the UI when all are opened
|
||||
setState(() {
|
||||
reactionsToMyMessages = tmpReactionsToMyMessages;
|
||||
reactionsToOtherMessages = tmpTeactionsToOtherMessages;
|
||||
messages = displayedMessages;
|
||||
});
|
||||
// }
|
||||
});
|
||||
}
|
||||
|
||||
Future _sendMessage() async {
|
||||
if (newMessageController.text == "" || user == null) return;
|
||||
if (newMessageController.text == "") return;
|
||||
await sendTextMessage(
|
||||
user!.userId,
|
||||
user.userId,
|
||||
TextMessageContent(
|
||||
text: newMessageController.text,
|
||||
),
|
||||
|
|
@ -330,71 +331,67 @@ class _ChatItemDetailsViewState extends State<ChatItemDetailsView> {
|
|||
title: GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.push(context, MaterialPageRoute(builder: (context) {
|
||||
return ContactView(widget.userid);
|
||||
return ContactView(widget.contact.userId);
|
||||
}));
|
||||
},
|
||||
child: (user == null)
|
||||
? Container()
|
||||
: Row(
|
||||
children: [
|
||||
ContactAvatar(
|
||||
contact: user!,
|
||||
fontSize: 19,
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: Row(
|
||||
children: [
|
||||
Text(getContactDisplayName(user!)),
|
||||
SizedBox(width: 10),
|
||||
VerifiedShield(user!),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
child: Row(
|
||||
children: [
|
||||
ContactAvatar(
|
||||
contact: user,
|
||||
fontSize: 19,
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: Row(
|
||||
children: [
|
||||
Text(getContactDisplayName(user)),
|
||||
SizedBox(width: 10),
|
||||
VerifiedShield(user),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
body: SafeArea(
|
||||
child: Column(
|
||||
children: [
|
||||
if (user != null)
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: messages.length,
|
||||
reverse: true,
|
||||
itemBuilder: (context, i) {
|
||||
bool lastMessageFromSameUser = false;
|
||||
if (i > 0) {
|
||||
lastMessageFromSameUser =
|
||||
(messages[i - 1].messageOtherId == null &&
|
||||
messages[i].messageOtherId == null) ||
|
||||
(messages[i - 1].messageOtherId != null &&
|
||||
messages[i].messageOtherId != null);
|
||||
}
|
||||
Message msg = messages[i];
|
||||
List<Message> reactions = [];
|
||||
if (reactionsToMyMessages.containsKey(msg.messageId)) {
|
||||
reactions = reactionsToMyMessages[msg.messageId]!;
|
||||
}
|
||||
if (msg.messageOtherId != null &&
|
||||
reactionsToOtherMessages
|
||||
.containsKey(msg.messageOtherId!)) {
|
||||
reactions =
|
||||
reactionsToOtherMessages[msg.messageOtherId!]!;
|
||||
}
|
||||
return ChatListEntry(
|
||||
msg,
|
||||
user!,
|
||||
lastMessageFromSameUser,
|
||||
reactions,
|
||||
);
|
||||
},
|
||||
),
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: messages.length,
|
||||
reverse: true,
|
||||
itemBuilder: (context, i) {
|
||||
bool lastMessageFromSameUser = false;
|
||||
if (i > 0) {
|
||||
lastMessageFromSameUser =
|
||||
(messages[i - 1].messageOtherId == null &&
|
||||
messages[i].messageOtherId == null) ||
|
||||
(messages[i - 1].messageOtherId != null &&
|
||||
messages[i].messageOtherId != null);
|
||||
}
|
||||
Message msg = messages[i];
|
||||
List<Message> reactions = [];
|
||||
if (reactionsToMyMessages.containsKey(msg.messageId)) {
|
||||
reactions = reactionsToMyMessages[msg.messageId]!;
|
||||
}
|
||||
if (msg.messageOtherId != null &&
|
||||
reactionsToOtherMessages
|
||||
.containsKey(msg.messageOtherId!)) {
|
||||
reactions = reactionsToOtherMessages[msg.messageOtherId!]!;
|
||||
}
|
||||
return ChatListEntry(
|
||||
msg,
|
||||
user,
|
||||
lastMessageFromSameUser,
|
||||
reactions,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
bottom: 30, left: 20, right: 20, top: 10),
|
||||
|
|
|
|||
|
|
@ -173,6 +173,14 @@ class _UserListItem extends State<UserListItem> {
|
|||
lastUpdateTime();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
updateTime?.cancel();
|
||||
messagesNotOpenedStream.cancel();
|
||||
lastMessageStream.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void initStreams() {
|
||||
lastMessageStream = twonlyDatabase.messagesDao
|
||||
.watchLastMessage(widget.user.userId)
|
||||
|
|
@ -235,14 +243,6 @@ class _UserListItem extends State<UserListItem> {
|
|||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
updateTime?.cancel();
|
||||
super.dispose();
|
||||
messagesNotOpenedStream.cancel();
|
||||
lastMessageStream.cancel();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
int flameCounter = getFlameCounterFromContact(widget.user);
|
||||
|
|
@ -306,7 +306,7 @@ class _UserListItem extends State<UserListItem> {
|
|||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) {
|
||||
return ChatItemDetailsView(widget.user.userId);
|
||||
return ChatItemDetailsView(widget.user);
|
||||
}),
|
||||
);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -476,7 +476,7 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
|||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) {
|
||||
return ChatItemDetailsView(widget.contact.userId);
|
||||
return ChatItemDetailsView(widget.contact);
|
||||
}),
|
||||
);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import 'dart:async';
|
|||
import 'package:drift/drift.dart' hide Column;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:twonly/src/components/alert_dialog.dart';
|
||||
import 'package:twonly/src/database/daos/contacts_dao.dart';
|
||||
import 'package:twonly/src/database/tables/messages_table.dart';
|
||||
|
|
@ -29,6 +30,30 @@ class _SearchUsernameView extends State<SearchUsernameView> {
|
|||
bool _isLoading = false;
|
||||
bool hasRequestedUsers = false;
|
||||
|
||||
List<Contact> contacts = [];
|
||||
late StreamSubscription<List<Contact>> contactsStream;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
initStreams();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
contactsStream.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void initStreams() {
|
||||
contactsStream =
|
||||
twonlyDatabase.contactsDao.watchNotAcceptedContacts().listen((update) {
|
||||
setState(() {
|
||||
contacts = update;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Future _addNewUser(BuildContext context) async {
|
||||
final user = await getUser();
|
||||
if (user == null || user.username == searchUserName.text) {
|
||||
|
|
@ -105,9 +130,6 @@ class _SearchUsernameView extends State<SearchUsernameView> {
|
|||
);
|
||||
}
|
||||
|
||||
Stream<List<Contact>> contacts =
|
||||
twonlyDatabase.contactsDao.watchNotAcceptedContacts();
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(context.lang.searchUsernameTitle),
|
||||
|
|
@ -148,22 +170,12 @@ class _SearchUsernameView extends State<SearchUsernameView> {
|
|||
label: Text(context.lang.searchUsernameQrCodeBtn),
|
||||
),
|
||||
SizedBox(height: 30),
|
||||
if (hasRequestedUsers)
|
||||
if (contacts.isNotEmpty)
|
||||
HeadLineComponent(
|
||||
context.lang.searchUsernameNewFollowerTitle,
|
||||
),
|
||||
StreamBuilder(
|
||||
stream: contacts,
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData ||
|
||||
snapshot.data == null ||
|
||||
snapshot.data!.isEmpty) {
|
||||
hasRequestedUsers = false;
|
||||
return Container();
|
||||
}
|
||||
hasRequestedUsers = true;
|
||||
return Expanded(child: ContactsListView(snapshot.data!));
|
||||
},
|
||||
Expanded(
|
||||
child: ContactsListView(contacts),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
|
@ -194,6 +206,78 @@ class ContactsListView extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _ContactsListViewState extends State<ContactsListView> {
|
||||
List<Widget> sendRequestActions(Contact contact) {
|
||||
return [
|
||||
Tooltip(
|
||||
message: context.lang.searchUserNameArchiveUserTooltip,
|
||||
child: IconButton(
|
||||
icon: FaIcon(FontAwesomeIcons.boxArchive, size: 15),
|
||||
onPressed: () async {
|
||||
final update = ContactsCompanion(archived: Value(true));
|
||||
await twonlyDatabase.contactsDao
|
||||
.updateContact(contact.userId, update);
|
||||
},
|
||||
),
|
||||
),
|
||||
Text(context.lang.searchUserNamePending),
|
||||
];
|
||||
}
|
||||
|
||||
List<Widget> requestedActions(Contact contact) {
|
||||
return [
|
||||
Tooltip(
|
||||
message: context.lang.searchUserNameBlockUserTooltip,
|
||||
child: IconButton(
|
||||
icon: Icon(Icons.person_off_rounded,
|
||||
color: const Color.fromARGB(164, 244, 67, 54)),
|
||||
onPressed: () async {
|
||||
final update = ContactsCompanion(blocked: Value(true));
|
||||
await twonlyDatabase.contactsDao
|
||||
.updateContact(contact.userId, update);
|
||||
},
|
||||
),
|
||||
),
|
||||
Tooltip(
|
||||
message: context.lang.searchUserNameRejectUserTooltip,
|
||||
child: IconButton(
|
||||
icon: Icon(Icons.close, color: Colors.red),
|
||||
onPressed: () async {
|
||||
await twonlyDatabase.contactsDao
|
||||
.deleteContactByUserId(contact.userId);
|
||||
encryptAndSendMessage(
|
||||
null,
|
||||
contact.userId,
|
||||
MessageJson(
|
||||
kind: MessageKind.rejectRequest,
|
||||
timestamp: DateTime.now(),
|
||||
content: MessageContent(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.check, color: Colors.green),
|
||||
onPressed: () async {
|
||||
final update = ContactsCompanion(accepted: Value(true));
|
||||
await twonlyDatabase.contactsDao
|
||||
.updateContact(contact.userId, update);
|
||||
await encryptAndSendMessage(
|
||||
null,
|
||||
contact.userId,
|
||||
MessageJson(
|
||||
kind: MessageKind.acceptRequest,
|
||||
timestamp: DateTime.now(),
|
||||
content: MessageContent(),
|
||||
),
|
||||
pushKind: PushKind.acceptRequest,
|
||||
);
|
||||
notifyContactsAboutProfileChange();
|
||||
},
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListView.builder(
|
||||
|
|
@ -206,61 +290,9 @@ class _ContactsListViewState extends State<ContactsListView> {
|
|||
leading: ContactAvatar(contact: contact),
|
||||
trailing: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (!contact.requested) Text('Pending'),
|
||||
if (contact.requested) ...[
|
||||
Tooltip(
|
||||
message: "Block the user without informing.",
|
||||
child: IconButton(
|
||||
icon: Icon(Icons.person_off_rounded,
|
||||
color: const Color.fromARGB(164, 244, 67, 54)),
|
||||
onPressed: () async {
|
||||
final update = ContactsCompanion(blocked: Value(true));
|
||||
await twonlyDatabase.contactsDao
|
||||
.updateContact(contact.userId, update);
|
||||
},
|
||||
),
|
||||
),
|
||||
Tooltip(
|
||||
message: "Reject the request and let the requester know.",
|
||||
child: IconButton(
|
||||
icon: Icon(Icons.close, color: Colors.red),
|
||||
onPressed: () async {
|
||||
await twonlyDatabase.contactsDao
|
||||
.deleteContactByUserId(contact.userId);
|
||||
encryptAndSendMessage(
|
||||
null,
|
||||
contact.userId,
|
||||
MessageJson(
|
||||
kind: MessageKind.rejectRequest,
|
||||
timestamp: DateTime.now(),
|
||||
content: MessageContent(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.check, color: Colors.green),
|
||||
onPressed: () async {
|
||||
final update = ContactsCompanion(accepted: Value(true));
|
||||
await twonlyDatabase.contactsDao
|
||||
.updateContact(contact.userId, update);
|
||||
encryptAndSendMessage(
|
||||
null,
|
||||
contact.userId,
|
||||
MessageJson(
|
||||
kind: MessageKind.acceptRequest,
|
||||
timestamp: DateTime.now(),
|
||||
content: MessageContent(),
|
||||
),
|
||||
pushKind: PushKind.acceptRequest,
|
||||
);
|
||||
notifyContactsAboutProfileChange();
|
||||
},
|
||||
),
|
||||
],
|
||||
],
|
||||
children: contact.requested
|
||||
? requestedActions(contact)
|
||||
: sendRequestActions(contact),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue