Support core status check and force restart Optimize proxies page and access page Update flutter and pub dependencies Update go version Optimize more details
152 lines
5.0 KiB
Dart
152 lines
5.0 KiB
Dart
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),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|