From 5447f3464e2ff4d4a8a7914191e3065362b7a645 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Tue, 17 Jun 2025 11:25:15 -0400 Subject: [PATCH] chore: some fixes for the timer --- lib/pages/chat/events/message.dart | 9 +- .../activities/activity_aware_builder.dart | 62 +++++++++++ .../activities/activity_state_event.dart | 4 +- lib/pangea/activities/countdown.dart | 26 +---- .../activities/pinned_activity_message.dart | 103 +++++++++--------- 5 files changed, 132 insertions(+), 72 deletions(-) create mode 100644 lib/pangea/activities/activity_aware_builder.dart diff --git a/lib/pages/chat/events/message.dart b/lib/pages/chat/events/message.dart index e98bb7554..0fd7e79bc 100644 --- a/lib/pages/chat/events/message.dart +++ b/lib/pages/chat/events/message.dart @@ -125,7 +125,14 @@ class Message extends StatelessWidget { } // #Pangea if (event.type == PangeaEventTypes.activityPlan) { - return ActivityStateEvent(event: event); + final state = event.room.getState(PangeaEventTypes.activityPlan); + if (state == null || state is! Event) { + return const SizedBox.shrink(); + } + + return state.originServerTs == event.originServerTs + ? ActivityStateEvent(event: event) + : const SizedBox(); } // Pangea# return StateMessage(event); diff --git a/lib/pangea/activities/activity_aware_builder.dart b/lib/pangea/activities/activity_aware_builder.dart new file mode 100644 index 000000000..68eea54af --- /dev/null +++ b/lib/pangea/activities/activity_aware_builder.dart @@ -0,0 +1,62 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; + +class ActivityAwareBuilder extends StatefulWidget { + final DateTime? deadline; + final Widget Function(bool) builder; + + const ActivityAwareBuilder({ + super.key, + required this.builder, + this.deadline, + }); + + @override + State createState() => ActivityAwareBuilderState(); +} + +class ActivityAwareBuilderState extends State { + Timer? _timer; + + @override + void initState() { + super.initState(); + _setTimer(); + } + + @override + void didUpdateWidget(covariant ActivityAwareBuilder oldWidget) { + super.didUpdateWidget(oldWidget); + if (oldWidget.deadline != widget.deadline) { + _setTimer(); + } + } + + @override + void dispose() { + _timer?.cancel(); + super.dispose(); + } + + void _setTimer() { + final now = DateTime.now(); + final delay = widget.deadline?.difference(now); + + if (delay != null && delay > Duration.zero) { + _timer?.cancel(); + _timer = Timer(delay, () { + _timer?.cancel(); + _timer = null; + if (mounted) setState(() {}); + }); + } + } + + @override + Widget build(BuildContext context) { + return widget.builder( + widget.deadline != null && widget.deadline!.isAfter(DateTime.now()), + ); + } +} diff --git a/lib/pangea/activities/activity_state_event.dart b/lib/pangea/activities/activity_state_event.dart index 97715632e..1f7a250e5 100644 --- a/lib/pangea/activities/activity_state_event.dart +++ b/lib/pangea/activities/activity_state_event.dart @@ -26,7 +26,7 @@ class ActivityStateEvent extends StatefulWidget { } class ActivityStateEventState extends State { - late final Timer _timer; + Timer? _timer; @override void initState() { @@ -45,7 +45,7 @@ class ActivityStateEventState extends State { @override void dispose() { - _timer.cancel(); + _timer?.cancel(); super.dispose(); } diff --git a/lib/pangea/activities/countdown.dart b/lib/pangea/activities/countdown.dart index f0ed5e48d..17516cb23 100644 --- a/lib/pangea/activities/countdown.dart +++ b/lib/pangea/activities/countdown.dart @@ -22,7 +22,7 @@ class CountDown extends StatefulWidget { } class CountDownState extends State { - late Timer _timer; + Timer? _timer; @override void initState() { @@ -30,23 +30,11 @@ class CountDownState extends State { _timer = Timer.periodic(const Duration(seconds: 1), (_) { setState(() {}); }); - - // final now = DateTime.now(); - // final delay = widget.deadline?.difference(now); - - // if (delay != null && delay > Duration.zero) { - // _endTimer = Timer(delay, () { - // setState( - // () => setState(() {}), - // ); - // }); - // } } @override void dispose() { - _timer.cancel(); - // _endTimer.cancel(); + _timer?.cancel(); super.dispose(); } @@ -66,20 +54,18 @@ class CountDownState extends State { return parts.join(" "); } - Duration? get remainingTime { + Duration? get _remainingTime { if (widget.deadline == null) { return null; } final now = DateTime.now(); - return widget.deadline!.isAfter(now) - ? widget.deadline!.difference(now) - : Duration.zero; + return widget.deadline!.difference(now); } @override Widget build(BuildContext context) { - final remainingTime = this.remainingTime; + final remainingTime = _remainingTime; final durationString = _formatDuration(remainingTime ?? Duration.zero); return ConstrainedBox( @@ -98,7 +84,7 @@ class CountDownState extends State { Flexible( child: Text( remainingTime != null && - remainingTime > Duration.zero && + remainingTime >= Duration.zero && durationString != null ? durationString : L10n.of(context).duration, diff --git a/lib/pangea/activities/pinned_activity_message.dart b/lib/pangea/activities/pinned_activity_message.dart index 32554058e..8be5a492f 100644 --- a/lib/pangea/activities/pinned_activity_message.dart +++ b/lib/pangea/activities/pinned_activity_message.dart @@ -7,6 +7,7 @@ import 'package:matrix/matrix.dart'; import 'package:fluffychat/pages/chat/chat.dart'; import 'package:fluffychat/pages/chat/chat_app_bar_list_tile.dart'; +import 'package:fluffychat/pangea/activities/activity_aware_builder.dart'; import 'package:fluffychat/pangea/activities/activity_duration_popup.dart'; import 'package:fluffychat/pangea/activities/countdown.dart'; import 'package:fluffychat/pangea/activity_planner/activity_plan_model.dart'; @@ -34,62 +35,66 @@ class PinnedActivityMessage extends StatelessWidget { Widget build(BuildContext context) { final theme = Theme.of(context); - if (_activityPlan?.endAt == null || - _activityPlan!.endAt!.isBefore(DateTime.now())) { - return const SizedBox.shrink(); - } + return ActivityAwareBuilder( + deadline: _activityPlan?.endAt, + builder: (isActive) { + if (!isActive || _activityPlan == null) { + return const SizedBox.shrink(); + } - return ChatAppBarListTile( - title: _activityPlan!.title, - leading: IconButton( - splashRadius: 18, - iconSize: 18, - color: theme.colorScheme.onSurfaceVariant, - icon: const Icon(Icons.push_pin), - onPressed: () {}, - ), - trailing: Padding( - padding: const EdgeInsets.only(right: 16.0), - child: InkWell( - borderRadius: BorderRadius.circular(20), - onTap: () async { - final Duration? duration = await showDialog( - context: context, - builder: (context) { - return ActivityDurationPopup( - initialValue: - _activityPlan?.duration ?? const Duration(days: 1), + return ChatAppBarListTile( + title: _activityPlan!.title, + leading: IconButton( + splashRadius: 18, + iconSize: 18, + color: theme.colorScheme.onSurfaceVariant, + icon: const Icon(Icons.push_pin), + onPressed: () {}, + ), + trailing: Padding( + padding: const EdgeInsets.only(right: 16.0), + child: InkWell( + borderRadius: BorderRadius.circular(20), + onTap: () async { + final Duration? duration = await showDialog( + context: context, + builder: (context) { + return ActivityDurationPopup( + initialValue: + _activityPlan?.duration ?? const Duration(days: 1), + ); + }, + ); + + if (duration == null) return; + + showFutureLoadingDialog( + context: context, + future: () => controller.room.sendActivityPlan( + _activityPlan!.copyWith( + endAt: DateTime.now().add(duration), + duration: duration, + ), + ), ); }, - ); - - if (duration == null) return; - - showFutureLoadingDialog( - context: context, - future: () => controller.room.sendActivityPlan( - _activityPlan!.copyWith( - endAt: DateTime.now().add(duration), - duration: duration, + child: Container( + padding: const EdgeInsets.all(4.0), + decoration: BoxDecoration( + color: theme.colorScheme.primaryContainer, + borderRadius: BorderRadius.circular(20), + ), + child: CountDown( + deadline: _activityPlan!.endAt, + iconSize: 16.0, + textSize: 14.0, ), ), - ); - }, - child: Container( - padding: const EdgeInsets.all(4.0), - decoration: BoxDecoration( - color: theme.colorScheme.primaryContainer, - borderRadius: BorderRadius.circular(20), - ), - child: CountDown( - deadline: _activityPlan!.endAt, - iconSize: 16.0, - textSize: 14.0, ), ), - ), - ), - onTap: _scrollToEvent, + onTap: _scrollToEvent, + ); + }, ); } }