Eliminate multiple click through events and put up snackbar if loading before navigating to new screen

merge-requests/67/merge
Hank Grabowski 2024-12-19 22:08:51 -05:00
rodzic 82c791bb21
commit 0b66b3806f
2 zmienionych plików z 64 dodań i 18 usunięć

Wyświetl plik

@ -17,18 +17,31 @@ import '../utils/snackbar_builder.dart';
import 'html_text_viewer_control.dart';
import 'image_control.dart';
class NotificationControl extends ConsumerWidget {
static final _logger = Logger('$NotificationControl');
final UserNotification notification;
bool _processingTap = false;
final _logger = Logger('$NotificationControl');
NotificationControl({
class NotificationControl extends ConsumerStatefulWidget {
final UserNotification notification;
const NotificationControl({
super.key,
required this.notification,
});
@override
ConsumerState<NotificationControl> createState() =>
_NotificationControlState();
}
class _NotificationControlState extends ConsumerState<NotificationControl> {
bool _processingTap = false;
UserNotification get notification => widget.notification;
Future<void> _goToStatus(
BuildContext context, WidgetRef ref, Profile profile) async {
BuildContext context,
WidgetRef ref,
Profile profile,
) async {
final existingPostData =
ref.read(postTreeEntryByIdProvider(profile, notification.iid));
if (existingPostData.isSuccess) {
@ -36,6 +49,8 @@ class NotificationControl extends ConsumerWidget {
.push('/post/view/${existingPostData.value.id}/${notification.iid}');
return;
}
buildSnackbar(context, 'Fetching status to load');
final loadedPost = await ref
.read(timelineUpdaterProvider(profile).notifier)
.refreshStatusChain(notification.iid);
@ -52,7 +67,7 @@ class NotificationControl extends ConsumerWidget {
}
@override
Widget build(BuildContext context, WidgetRef ref) {
Widget build(BuildContext context) {
final profile = ref.watch(activeProfileProvider);
const iconSize = 50.0;
@ -114,7 +129,7 @@ class NotificationControl extends ConsumerWidget {
break;
}
final onTap = onTapCallFunction == null
final onTap = _processingTap || onTapCallFunction == null
? null
: () async {
if (_processingTap) {
@ -165,11 +180,19 @@ class NotificationControl extends ConsumerWidget {
}
void _tapProcessingStarted() {
_processingTap = true;
Future.delayed(const Duration(seconds: 10), () => _processingTap = false);
setState(() {
_processingTap = true;
});
Future.delayed(const Duration(seconds: 20), () {
if (mounted) {
_tapProcessingStop();
}
});
}
void _tapProcessingStop() {
_processingTap = false;
setState(() {
_processingTap = false;
});
}
}

Wyświetl plik

@ -58,6 +58,7 @@ class _StatusControlState extends ConsumerState<FlattenedTreeEntryControl> {
var showComments = false;
var isProcessing = false;
var filteringInfo = FilterResult.show;
var _processingTap = false;
bool get isMine => widget.originalItem.isMine;
@ -137,11 +138,18 @@ class _StatusControlState extends ConsumerState<FlattenedTreeEntryControl> {
bottom: otherPadding,
),
child: GestureDetector(
onTap: () {
if (widget.showStatusOpenButton) {
_goToPostView(entry);
}
},
onTap: _processingTap
? null
: () {
if (widget.showStatusOpenButton) {
if (_processingTap) {
return;
}
_tapProcessingStarted();
_goToPostView(entry);
_tapProcessingStop();
}
},
child: bodyCard),
);
}
@ -151,8 +159,6 @@ class _StatusControlState extends ConsumerState<FlattenedTreeEntryControl> {
Profile profile,
TimelineEntry entry,
) {
_logger.info(
'Show content? $showContent Show spoiler? $showSpoilerControl Has Spoiler Text? ${entry.spoilerText.isNotEmpty}');
return Padding(
padding: const EdgeInsets.all(5.0),
child: Column(
@ -417,6 +423,23 @@ class _StatusControlState extends ConsumerState<FlattenedTreeEntryControl> {
void _goToPostView(TimelineEntry entry) {
context.push('/post/view/${entry.id}/${entry.id}');
}
void _tapProcessingStarted() {
setState(() {
_processingTap = true;
});
Future.delayed(const Duration(seconds: 20), () {
if (mounted) {
_tapProcessingStop();
}
});
}
void _tapProcessingStop() {
setState(() {
_processingTap = false;
});
}
}
extension _TimelineExtensions on TimelineEntry {