relatica/lib/controls/notifications_control.dart

154 wiersze
5.0 KiB
Dart

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:logging/logging.dart';
import 'package:provider/provider.dart';
import 'package:result_monad/result_monad.dart';
import '../globals.dart';
import '../models/exec_error.dart';
import '../models/user_notification.dart';
import '../routes.dart';
import '../services/connections_manager.dart';
import '../services/notifications_manager.dart';
import '../services/timeline_manager.dart';
import '../utils/active_profile_selector.dart';
import '../utils/dateutils.dart';
import '../utils/snackbar_builder.dart';
import 'html_text_viewer_control.dart';
import 'image_control.dart';
class NotificationControl extends StatelessWidget {
static final _logger = Logger('$NotificationControl');
final UserNotification notification;
const NotificationControl({
super.key,
required this.notification,
});
Future<void> _goToStatus(BuildContext context) async {
final manager =
getIt<ActiveProfileSelector<TimelineManager>>().activeEntry.value;
final existingPostData = manager.getPostTreeEntryBy(notification.iid);
if (existingPostData.isSuccess) {
context
.push('/post/view/${existingPostData.value.id}/${notification.iid}');
return;
}
final loadedPost = await manager.refreshStatusChain(notification.iid);
if (loadedPost.isSuccess) {
context.push('/post/view/${loadedPost.value.id}/${notification.iid}');
return;
}
buildSnackbar(
context, 'Error getting data for notification: ${loadedPost.error}');
}
@override
Widget build(BuildContext context) {
const iconSize = 50.0;
final manager = context
.watch<ActiveProfileSelector<NotificationsManager>>()
.activeEntry
.fold(
onSuccess: (manager) => manager,
onError: (error) {
_logger.severe('Error getting notification manager: $error');
return null;
},
);
final fromIcon = getIt<ActiveProfileSelector<ConnectionsManager>>()
.activeEntry
.andThen((manager) => manager.getById(notification.fromId))
.fold(
onSuccess: (connection) => ImageControl(
imageUrl: connection.avatarUrl.toString(),
iconOverride: const Icon(Icons.person),
width: iconSize,
height: iconSize,
onTap: () async {
context.pushNamed(ScreenPaths.userProfile,
pathParameters: {'id': notification.fromId});
},
),
onError: (error) => GestureDetector(
onTap: () async {
context.pushNamed(ScreenPaths.userProfile,
pathParameters: {'id': notification.fromId});
},
child: const SizedBox(
width: iconSize,
height: iconSize,
child: Icon(Icons.person),
),
),
);
Function()? onTap;
switch (notification.type) {
case NotificationType.follow:
onTap = () {
context.pushNamed(ScreenPaths.userProfile,
pathParameters: {'id': notification.fromId});
};
break;
case NotificationType.follow_request:
onTap = () {
context.push('/connect/${notification.fromId}');
};
break;
case NotificationType.unknown:
buildSnackbar(context, 'Unknown message type, nothing to do');
break;
case NotificationType.favourite:
case NotificationType.mention:
case NotificationType.reshare:
case NotificationType.reblog:
case NotificationType.status:
onTap = () {
_goToStatus(context);
};
break;
case NotificationType.direct_message:
onTap = () => context.pushNamed(
ScreenPaths.thread,
queryParameters: {'uri': notification.iid},
);
break;
}
return ListTile(
tileColor: notification.dismissed ? null : Colors.black12,
leading: fromIcon,
title: GestureDetector(
onTap: onTap == null ? null : () async => onTap!(),
child: HtmlTextViewerControl(
content: notification.content,
onTapUrl: onTap == null ? null : (_) async => onTap!(),
),
),
subtitle: GestureDetector(
onTap: onTap == null ? null : () async => onTap!(),
child: Text(
ElapsedDateUtils.epochSecondsToString(notification.timestamp),
),
),
trailing: notification.dismissed ||
notification.type == NotificationType.direct_message
? null
: IconButton(
onPressed: manager == null
? null
: () async {
await manager.markSeen(notification).withError((error) {
buildSnackbar(
context, 'Error marking notification: $error');
logError(error, _logger);
});
},
icon: const Icon(Icons.close_rounded)),
);
}
}