2024-02-17 20:32:01 +05:30
|
|
|
import "package:auto_route/auto_route.dart";
|
|
|
|
|
import "package:flutter/material.dart";
|
2026-09-26 22:45:38 +03:00
|
|
|
import "package:flutter_riverpod/flutter_riverpod.dart";
|
2024-02-17 20:32:01 +05:30
|
|
|
|
2026-09-26 22:45:38 +03:00
|
|
|
import "package:smol_mail/data/providers/providers.dart";
|
|
|
|
|
import "package:smol_mail/presentation/routes/app_router.gr.dart";
|
|
|
|
|
import "package:smol_mail/presentation/theme/app_colors.dart";
|
|
|
|
|
import "package:smol_mail/shared/utils/avatar_color.dart";
|
|
|
|
|
import "package:smol_mail/shared/utils/format.dart";
|
|
|
|
|
import "package:smol_mail/smol/proto.dart";
|
|
|
|
|
import "package:smol_mail/smol/store.dart";
|
2024-02-17 20:32:01 +05:30
|
|
|
|
2026-09-26 22:45:38 +03:00
|
|
|
class MessageTile extends ConsumerWidget {
|
|
|
|
|
final MailRecord record;
|
2024-02-17 20:32:01 +05:30
|
|
|
|
2026-09-26 22:45:38 +03:00
|
|
|
const MessageTile({super.key, required this.record});
|
2024-02-17 20:32:01 +05:30
|
|
|
|
|
|
|
|
@override
|
2026-09-26 22:45:38 +03:00
|
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
|
|
|
final folder = ref.watch(folderProvider);
|
|
|
|
|
final store = ref.watch(storeProvider);
|
|
|
|
|
final opened = ref.read(clientProvider).describe(record);
|
|
|
|
|
final appColors = Theme.of(context).extension<AppColors>()!;
|
2024-02-17 20:32:01 +05:30
|
|
|
|
2026-09-26 22:45:38 +03:00
|
|
|
String who;
|
|
|
|
|
if (folder == "sent") {
|
|
|
|
|
who = record.recipient ?? "";
|
|
|
|
|
} else if (opened.sender != null) {
|
|
|
|
|
final known = store.addressForKey(opened.sender!);
|
|
|
|
|
who = known ?? "unknown · ${b32encode(opened.sender!).substring(0, 4)}";
|
|
|
|
|
} else {
|
|
|
|
|
who = "?";
|
|
|
|
|
}
|
|
|
|
|
final unread = folder == "inbox" && !store.isRead(record.id);
|
|
|
|
|
final errorText = opened.error != null ? "<unreadable>" : null;
|
|
|
|
|
final subject =
|
|
|
|
|
errorText ?? (opened.subject.isEmpty ? "(no subject)" : opened.subject);
|
|
|
|
|
final snippet = errorText == null
|
|
|
|
|
? opened.body.replaceAll(RegExp(r"\s+"), " ").trim()
|
|
|
|
|
: "";
|
|
|
|
|
final avatarColor = colorForKey(who, appColors.avatarPalette);
|
2024-02-17 20:32:01 +05:30
|
|
|
|
|
|
|
|
return ListTile(
|
2026-09-26 22:45:38 +03:00
|
|
|
splashColor: appColors.highlight,
|
|
|
|
|
focusColor: appColors.cardFill,
|
|
|
|
|
onTap: () {
|
|
|
|
|
if (folder == "inbox") {
|
|
|
|
|
store.markRead(record.id);
|
|
|
|
|
ref.read(revisionProvider.notifier).bump();
|
|
|
|
|
}
|
|
|
|
|
AutoRouter.of(context).push(
|
|
|
|
|
MessageDetailRoute(folder: folder, id: record.id),
|
|
|
|
|
);
|
|
|
|
|
},
|
2024-02-17 20:32:01 +05:30
|
|
|
leading: CircleAvatar(
|
|
|
|
|
radius: 25,
|
2026-09-26 22:45:38 +03:00
|
|
|
backgroundColor: avatarColor,
|
2024-02-17 20:32:01 +05:30
|
|
|
child: Text(
|
2026-09-26 22:45:38 +03:00
|
|
|
who.isEmpty ? "?" : who[0].toUpperCase(),
|
2024-02-17 20:32:01 +05:30
|
|
|
style: Theme.of(context).textTheme.bodyLarge!.copyWith(
|
2026-09-26 22:45:38 +03:00
|
|
|
color: contrastingTextColor(avatarColor),
|
2024-02-17 20:32:01 +05:30
|
|
|
fontWeight: FontWeight.w500,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
title: Text(
|
2026-09-26 22:45:38 +03:00
|
|
|
who,
|
|
|
|
|
maxLines: 1,
|
|
|
|
|
overflow: TextOverflow.ellipsis,
|
2024-02-17 20:32:01 +05:30
|
|
|
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
2026-09-26 22:45:38 +03:00
|
|
|
fontWeight: unread ? FontWeight.bold : FontWeight.w500,
|
2024-02-17 20:32:01 +05:30
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
subtitle: Column(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
children: [
|
|
|
|
|
Text(
|
2026-09-26 22:45:38 +03:00
|
|
|
subject,
|
2024-02-17 20:32:01 +05:30
|
|
|
overflow: TextOverflow.ellipsis,
|
|
|
|
|
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
2026-09-26 22:45:38 +03:00
|
|
|
fontWeight: unread ? FontWeight.w500 : FontWeight.w300,
|
2024-02-17 20:32:01 +05:30
|
|
|
),
|
|
|
|
|
),
|
2026-09-26 22:45:38 +03:00
|
|
|
if (snippet.isNotEmpty)
|
|
|
|
|
Text(
|
|
|
|
|
snippet.length > 140 ? snippet.substring(0, 140) : snippet,
|
|
|
|
|
overflow: TextOverflow.ellipsis,
|
|
|
|
|
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
|
|
|
|
color: appColors.snippetText,
|
|
|
|
|
),
|
|
|
|
|
)
|
2024-02-17 20:32:01 +05:30
|
|
|
],
|
|
|
|
|
),
|
2026-09-26 22:45:38 +03:00
|
|
|
trailing: Text(
|
|
|
|
|
formatShortTime(folder == "sent" ? record.sentAt : opened.time),
|
|
|
|
|
style: Theme.of(context).textTheme.labelSmall,
|
|
|
|
|
),
|
2024-02-17 20:32:01 +05:30
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-09-26 22:45:38 +03:00
|
|
|
|