twonly-app/lib/src/views/contact/contact.view.dart
otsmr bc1c61c8f8
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
finishing #327
2025-12-15 17:02:51 +01:00

286 lines
9.2 KiB
Dart

import 'dart:async';
import 'package:drift/drift.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/database/daos/contacts.dao.dart';
import 'package:twonly/src/database/twonly.db.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/views/components/alert_dialog.dart';
import 'package:twonly/src/views/components/avatar_icon.component.dart';
import 'package:twonly/src/views/components/better_list_title.dart';
import 'package:twonly/src/views/components/flame.dart';
import 'package:twonly/src/views/components/max_flame_list_title.dart';
import 'package:twonly/src/views/components/select_chat_deletion_time.comp.dart';
import 'package:twonly/src/views/components/verified_shield.dart';
import 'package:twonly/src/views/groups/group.view.dart';
import 'package:twonly/src/views/public_profile.view.dart';
class ContactView extends StatefulWidget {
const ContactView(this.userId, {super.key});
final int userId;
@override
State<ContactView> createState() => _ContactViewState();
}
class _ContactViewState extends State<ContactView> {
Future<void> handleUserRemoveRequest(Contact contact) async {
final remove = await showAlertDialog(
context,
context.lang
.contactRemoveTitle(getContactDisplayName(contact, maxLength: 20)),
context.lang.contactRemoveBody,
);
if (remove) {
await twonlyDB.contactsDao.updateContact(
contact.userId,
const ContactsCompanion(
accepted: Value(false),
requested: Value(false),
deletedByUser: Value(true),
),
);
if (mounted) {
Navigator.popUntil(context, (route) => route.isFirst);
}
}
}
Future<void> handleUserBlockRequest(Contact contact) async {
final block = await showAlertDialog(
context,
context.lang.contactBlockTitle(getContactDisplayName(contact)),
context.lang.contactBlockBody,
);
if (block) {
const update = ContactsCompanion(blocked: Value(true));
if (context.mounted) {
await twonlyDB.contactsDao.updateContact(contact.userId, update);
}
if (mounted) {
Navigator.popUntil(context, (route) => route.isFirst);
}
}
}
Future<void> handleReportUser(Contact contact) async {
final reason = await showReportDialog(context, contact);
if (reason == null) return;
final res = await apiService.reportUser(contact.userId, reason);
if (!mounted) return;
if (res.isSuccess) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.lang.userGotReported),
duration: const Duration(seconds: 3),
),
);
} else {
showNetworkIssue(context);
}
}
@override
Widget build(BuildContext context) {
final contact = twonlyDB.contactsDao
.getContactByUserId(widget.userId)
.watchSingleOrNull();
return Scaffold(
appBar: AppBar(
title: const Text(''),
),
body: StreamBuilder(
stream: contact,
builder: (context, snapshot) {
if (!snapshot.hasData || snapshot.data == null) {
return Container();
}
final contact = snapshot.data!;
return ListView(
key: ValueKey(contact.userId),
children: [
Padding(
padding: const EdgeInsets.all(10),
child: AvatarIcon(contactId: contact.userId, fontSize: 30),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(right: 10),
child: VerifiedShield(
key: GlobalKey(),
contact: contact,
),
),
Text(
getContactDisplayName(contact, maxLength: 20),
style: const TextStyle(fontSize: 20),
),
FlameCounterWidget(
contactId: contact.userId,
prefix: true,
),
],
),
if (getContactDisplayName(contact) != contact.username)
Center(child: Text('(${contact.username})')),
const SizedBox(height: 50),
BetterListTile(
icon: FontAwesomeIcons.pencil,
text: context.lang.contactNickname,
onTap: () async {
final nickName =
await showNicknameChangeDialog(context, contact);
if (context.mounted && nickName != null && nickName != '') {
final update = ContactsCompanion(nickName: Value(nickName));
await twonlyDB.contactsDao
.updateContact(contact.userId, update);
}
},
),
const Divider(),
SelectChatDeletionTimeListTitle(
groupId: getUUIDforDirectChat(widget.userId, gUser.userId),
),
const Divider(),
MaxFlameListTitle(
contactId: widget.userId,
),
BetterListTile(
icon: FontAwesomeIcons.shieldHeart,
text: context.lang.contactVerifyNumberTitle,
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const PublicProfileView();
},
),
);
setState(() {});
},
),
// BetterListTile(
// icon: FontAwesomeIcons.eraser,
// iconSize: 16,
// text: context.lang.deleteAllContactMessages,
// onTap: () async {
// final block = await showAlertDialog(
// context,
// context.lang.deleteAllContactMessages,
// context.lang.deleteAllContactMessagesBody(
// getContactDisplayName(contact),
// ),
// );
// if (block) {
// if (context.mounted) {
// await twonlyDB.messagesDao
// .deleteMessagesByContactId(contact.userId);
// }
// }
// },
// ),
BetterListTile(
icon: FontAwesomeIcons.flag,
text: context.lang.reportUser,
onTap: () => handleReportUser(contact),
),
BetterListTile(
icon: FontAwesomeIcons.ban,
text: context.lang.contactBlock,
onTap: () => handleUserBlockRequest(contact),
),
// BetterListTile(
// icon: FontAwesomeIcons.userMinus,
// iconSize: 16,
// color: Colors.red,
// text: context.lang.contactRemove,
// onTap: () => handleUserRemoveRequest(contact),
// ),
],
);
},
),
);
}
}
Future<String?> showNicknameChangeDialog(
BuildContext context,
Contact contact,
) {
final controller =
TextEditingController(text: getContactDisplayName(contact));
return showDialog<String>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text(context.lang.contactNickname),
content: TextField(
controller: controller,
autofocus: true,
decoration:
InputDecoration(hintText: context.lang.contactNicknameNew),
),
actions: <Widget>[
TextButton(
child: Text(context.lang.cancel),
onPressed: () {
Navigator.of(context).pop(); // Close the dialog
},
),
TextButton(
child: Text(context.lang.ok),
onPressed: () {
Navigator.of(context)
.pop(controller.text); // Return the input text
},
),
],
);
},
);
}
Future<String?> showReportDialog(
BuildContext context,
Contact contact,
) {
final controller = TextEditingController();
return showDialog<String>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title:
Text(context.lang.reportUserTitle(getContactDisplayName(contact))),
content: TextField(
controller: controller,
autofocus: true,
decoration: InputDecoration(hintText: context.lang.reportUserReason),
),
actions: <Widget>[
TextButton(
child: Text(context.lang.cancel),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: Text(context.lang.ok),
onPressed: () {
Navigator.of(context).pop(controller.text);
},
),
],
);
},
);
}