Files
MWClash/lib/manager/message_manager.dart

152 lines
5.0 KiB
Dart
Raw Normal View History

import 'dart:async';
import 'dart:collection';
import 'dart:math';
import 'package:fl_clash/common/common.dart';
import 'package:fl_clash/models/models.dart';
import 'package:fl_clash/widgets/fade_box.dart';
import 'package:flutter/material.dart';
class MessageManager extends StatefulWidget {
final Widget child;
const MessageManager({super.key, required this.child});
@override
State<MessageManager> createState() => MessageManagerState();
}
class MessageManagerState extends State<MessageManager> {
final _messagesNotifier = ValueNotifier<List<CommonMessage>>([]);
final _bufferMessages = Queue<CommonMessage>();
final _activeTimers = <String, Timer>{};
bool _isDisplayingMessage = false;
@override
void initState() {
super.initState();
}
@override
void dispose() {
_messagesNotifier.dispose();
for (final timer in _activeTimers.values) {
timer.cancel();
}
_activeTimers.clear();
_bufferMessages.clear();
super.dispose();
}
void message(String text) {
final commonMessage = CommonMessage(id: utils.uuidV4, text: text);
_bufferMessages.add(commonMessage);
commonPrint.log('message: $text');
_processQueue();
}
void _cancelMessage(String id) {
_bufferMessages.removeWhere((msg) => msg.id == id);
if (_activeTimers.containsKey(id)) {
_removeMessage(id);
}
}
void _processQueue() {
if (_isDisplayingMessage || _bufferMessages.isEmpty) {
return;
}
_isDisplayingMessage = true;
final message = _bufferMessages.removeFirst();
_messagesNotifier.value = List.from(_messagesNotifier.value)..add(message);
final timer = Timer(message.duration, () {
_removeMessage(message.id);
});
_activeTimers[message.id] = timer;
}
void _removeMessage(String id) {
_activeTimers.remove(id)?.cancel();
final currentMessages = List<CommonMessage>.from(_messagesNotifier.value);
currentMessages.removeWhere((msg) => msg.id == id);
_messagesNotifier.value = currentMessages;
_isDisplayingMessage = false;
_processQueue();
}
@override
Widget build(BuildContext context) {
return Stack(
children: [
widget.child,
ValueListenableBuilder(
valueListenable: _messagesNotifier,
builder: (_, messages, _) {
return Container(
margin: EdgeInsets.only(
top: kToolbarHeight + 12,
left: 12,
right: 12,
),
child: FadeThroughBox(
alignment: Alignment.topRight,
child: messages.isEmpty
? SizedBox()
: LayoutBuilder(
key: Key(messages.last.id),
builder: (_, constraints) {
return Dismissible(
key: ValueKey(messages.last.id),
onDismissed: (_) {
_cancelMessage(messages.last.id);
},
child: Card(
shape: const RoundedSuperellipseBorder(
borderRadius: BorderRadius.all(
Radius.circular(14),
),
),
elevation: 10,
color: context.colorScheme.surfaceContainerHigh,
child: Container(
width: min(constraints.maxWidth, 500),
padding: EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Flexible(
child: Text(
messages.last.text,
maxLines: 3,
overflow: TextOverflow.ellipsis,
),
),
SizedBox(width: 16),
IconButton(
padding: EdgeInsets.all(2),
visualDensity: VisualDensity.compact,
onPressed: () {
_cancelMessage(messages.last.id);
},
icon: Icon(Icons.close),
),
],
),
),
),
);
},
),
),
);
},
),
],
);
}
}