twonly-app/lib/src/views/chats/chat_list_view.dart
2025-02-10 20:16:30 +01:00

238 lines
7.6 KiB
Dart

import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:provider/provider.dart';
import 'package:twonly/src/components/flame.dart';
import 'package:twonly/src/components/initialsavatar.dart';
import 'package:twonly/src/components/message_send_state_icon.dart';
import 'package:twonly/src/components/notification_badge.dart';
import 'package:twonly/src/components/user_context_menu.dart';
import 'package:twonly/src/model/contacts_model.dart';
import 'package:twonly/src/model/json/message.dart';
import 'package:twonly/src/model/messages_model.dart';
import 'package:twonly/src/providers/api/api.dart';
import 'package:twonly/src/providers/contacts_change_provider.dart';
import 'package:twonly/src/providers/download_change_provider.dart';
import 'package:twonly/src/providers/messages_change_provider.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/views/chats/chat_item_details_view.dart';
import 'package:twonly/src/views/chats/media_viewer_view.dart';
import 'package:twonly/src/views/settings/settings_main_view.dart';
import 'package:twonly/src/views/chats/search_username_view.dart';
import 'package:flutter/material.dart';
/// Displays a list of SampleItems.
class ChatListView extends StatefulWidget {
const ChatListView({super.key});
@override
State<ChatListView> createState() => _ChatListViewState();
}
class _ChatListViewState extends State<ChatListView> {
@override
Widget build(BuildContext context) {
Map<int, DbMessage> lastMessages =
context.watch<MessagesChangeProvider>().lastMessage;
List<Contact> allUsers = context
.watch<ContactChangeProvider>()
.allContacts
.where((c) => c.accepted)
.toList();
allUsers.sort((b, a) {
DbMessage? msgA = lastMessages[a.userId.toInt()];
DbMessage? msgB = lastMessages[a.userId.toInt()];
if (msgA == null) return 1;
if (msgB == null) return -1;
return msgA.sendAt.compareTo(msgB.sendAt);
});
int maxTotalMediaCounter = 0;
if (allUsers.isNotEmpty) {
maxTotalMediaCounter = allUsers
.map((x) => x.totalMediaCounter)
.reduce((a, b) => a > b ? a : b);
}
return Scaffold(
appBar: AppBar(
title: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProfileView(),
),
);
},
child: Text("twonly"),
),
// title:
actions: [
NotificationBadge(
count: context
.watch<ContactChangeProvider>()
.newContactRequests
.toString(),
child: IconButton(
icon: FaIcon(FontAwesomeIcons.userPlus, size: 18),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SearchUsernameView(),
),
);
},
),
),
IconButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProfileView(),
),
);
},
icon: FaIcon(FontAwesomeIcons.gear, size: 19),
)
],
),
body: (allUsers.isEmpty)
? Center(
child: Padding(
padding: const EdgeInsets.all(10),
child: OutlinedButton.icon(
icon: Icon(Icons.person_add),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SearchUsernameView(),
),
);
},
label: Text(context.lang.chatListViewSearchUserNameBtn)),
),
)
: ListView.builder(
restorationId: 'chat_list_view',
itemCount: allUsers.length,
itemBuilder: (BuildContext context, int index) {
final user = allUsers[index];
return UserListItem(
user: user,
maxTotalMediaCounter: maxTotalMediaCounter,
lastMessage: lastMessages[user.userId.toInt()],
);
},
),
);
}
}
class UserListItem extends StatefulWidget {
final Contact user;
final DbMessage? lastMessage;
final int maxTotalMediaCounter;
const UserListItem(
{super.key,
required this.user,
required this.lastMessage,
required this.maxTotalMediaCounter});
@override
State<UserListItem> createState() => _UserListItem();
}
class _UserListItem extends State<UserListItem> {
int lastMessageInSeconds = 0;
MessageSendState state = MessageSendState.send;
bool isDownloading = false;
List<int> token = [];
@override
Widget build(BuildContext context) {
if (widget.lastMessage != null) {
lastMessageInSeconds =
DateTime.now().difference(widget.lastMessage!.sendAt).inSeconds;
state = widget.lastMessage!.getSendState();
final content = widget.lastMessage!.messageContent;
if (widget.lastMessage!.messageReceived &&
content is MediaMessageContent) {
token = content.downloadToken;
isDownloading = context
.watch<DownloadChangeProvider>()
.currentlyDownloading
.contains(token.toString());
}
}
int flameCounter = context
.watch<MessagesChangeProvider>()
.flamesCounter[widget.user.userId.toInt()] ??
0;
return UserContextMenu(
user: widget.user,
child: ListTile(
title: Text(widget.user.displayName),
subtitle: (widget.lastMessage == null)
? Text("Tap to send your first image.")
: Row(
children: [
MessageSendStateIcon(widget.lastMessage!),
Text(""),
const SizedBox(width: 5),
Text(
formatDuration(lastMessageInSeconds),
style: TextStyle(fontSize: 12),
),
if (flameCounter > 0)
FlameCounterWidget(
widget.user,
flameCounter,
widget.maxTotalMediaCounter,
prefix: true,
),
],
),
leading: InitialsAvatar(displayName: widget.user.displayName),
onTap: () {
if (widget.lastMessage == null) {
print("TODO: implement sending to one person!");
return;
}
if (isDownloading) return;
if (!widget.lastMessage!.isDownloaded) {
tryDownloadMedia(widget.lastMessage!.messageId,
widget.lastMessage!.otherUserId, token,
force: true);
return;
}
if (state == MessageSendState.received &&
widget.lastMessage!.containsOtherMedia()) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return MediaViewerView(widget.user, widget.lastMessage!);
}),
);
return;
}
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return ChatItemDetailsView(user: widget.user);
}),
);
},
),
);
}
}