浏览代码

加入通知demo

gavin.chen 2 年之前
父节点
当前提交
cd7217c82a

+ 6 - 6
lib/calendar_page/calendar_left_panel.dart

@@ -1,6 +1,8 @@
 import 'package:calendar_view/calendar_page/mini_calendar/mini_calendar.dart';
 import 'package:calendar_view/calendar_page/my_calendar/my_calendar.dart';
+import 'package:calendar_view/notification_demo/notification_controller.dart';
 import 'package:flutter/material.dart';
+import 'package:get/get.dart';
 
 /// 日历视图左侧面板
 class CalendarLeftPanel extends StatefulWidget {
@@ -95,12 +97,10 @@ class _CalendarLeftPanelState extends State<CalendarLeftPanel> {
                       MaterialStateProperty.all<Color>(Colors.transparent),
                 ),
                 onPressed: (() {
-                  ScaffoldMessenger.of(context).showSnackBar(
-                    const SnackBar(
-                      duration: Duration(milliseconds: 500),
-                      content: Text('前方正在施工'),
-                    ),
-                  );
+                  ///FIXME: 临时测试用
+                  NotificationController notificationController =
+                      Get.find<NotificationController>();
+                  notificationController.sendMockNotification();
                 }),
                 child: const Icon(Icons.add),
               ),

+ 11 - 0
lib/calendar_page/month_calendar/schedule_item.dart

@@ -36,6 +36,17 @@ class _SchedualItemState extends State<SchedualItem> {
             ),
           );
         },
+
+        /// 接入双击后会导致单击反应变慢,暂时不接入
+        // onDoubleTap: () {
+        //   ScaffoldMessenger.of(context).showSnackBar(
+        //     SnackBar(
+        //       backgroundColor: scheduleType.color,
+        //       duration: const Duration(milliseconds: 500),
+        //       content: Text('双击了${scheduleType.typeName} 等待接入打开详情'),
+        //     ),
+        //   );
+        // },
         hoverColor: const Color.fromARGB(255, 227, 228, 228),
         child: Container(
           height: widget.itemHeight,

+ 2 - 1
lib/main.dart

@@ -1,4 +1,5 @@
 import 'package:calendar_view/calendar_page/calendar_page.dart';
+import 'package:calendar_view/notification_demo/global_notification_layer.dart';
 import 'package:flutter/material.dart';
 import 'package:get/get_navigation/src/root/get_material_app.dart';
 
@@ -36,7 +37,7 @@ class _MyHomePageState extends State<MyHomePage> {
   @override
   Widget build(BuildContext context) {
     return const Scaffold(
-      body: CalendarPage(),
+      body: GlobalNotificationLayer(child: CalendarPage()),
     );
   }
 }

+ 127 - 0
lib/notification_demo/global_notification_layer.dart

@@ -0,0 +1,127 @@
+import 'package:calendar_view/notification_demo/notification_card.dart';
+import 'package:calendar_view/notification_demo/notification_controller.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+
+/// 全局消息通知层
+class GlobalNotificationLayer extends StatefulWidget {
+  const GlobalNotificationLayer({Key? key, required this.child})
+      : super(key: key);
+  final Widget child;
+
+  @override
+  GlobalNotificationLayerState createState() => GlobalNotificationLayerState();
+}
+
+class GlobalNotificationLayerState extends State<GlobalNotificationLayer> {
+  late NotificationController notificationController;
+  List<SystemNotification> notifications = [];
+  final GlobalKey<AnimatedListState> _listKey = GlobalKey<AnimatedListState>();
+  final ScrollController _scrollController = ScrollController();
+
+  static final double _notificationWidth = 420;
+  @override
+  void initState() {
+    super.initState();
+    notificationController =
+        Get.put<NotificationController>(NotificationController());
+    notificationController.onReceiveNotification
+        .addListener(_onReceiveNotification);
+  }
+
+  @override
+  void dispose() {
+    super.dispose();
+    notificationController.onReceiveNotification
+        .removeListener(_onReceiveNotification);
+  }
+
+  void _onReceiveNotification(e, SystemNotification notification) {
+    _insertNotification(notifications.length, notification);
+  }
+
+  // 新增消息
+  void _insertNotification(index, SystemNotification item) {
+    if (_listKey.currentState is! AnimatedListState) return;
+    notifications.insert(index, item);
+    _listKey.currentState!.insertItem(index);
+  }
+
+  void _removeNotification(index) {
+    if (_listKey.currentState is! AnimatedListState) return;
+    _listKey.currentState!.removeItem(
+        index,
+        (context, animation) =>
+            _buildNotificationSizeOut(context, index, animation),
+        duration: const Duration(milliseconds: 120));
+
+    /// 延迟删除,避免动画过程中被重复删除
+    Future.delayed(const Duration(milliseconds: 120), () {
+      notifications.removeAt(index);
+    });
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Stack(
+      children: [
+        widget.child,
+        Positioned(
+          bottom: 0,
+          right: 0,
+          child: SizedBox(
+            width: _notificationWidth,
+            child: Align(
+              alignment: Alignment.bottomRight,
+              child: AnimatedList(
+                key: _listKey,
+                initialItemCount: notifications.length,
+                controller: _scrollController,
+                shrinkWrap: true,
+                itemBuilder: _buildNotificationFromRightSliderIn,
+              ),
+            ),
+          ),
+        ),
+      ],
+    );
+  }
+
+  // 从右侧划入
+  Widget _buildNotificationFromRightSliderIn(
+      BuildContext context, int index, Animation<double> animation) {
+    return SlideTransition(
+      position: Tween<Offset>(
+        begin: const Offset(1, 0),
+        end: Offset.zero,
+      ).animate(CurvedAnimation(
+          parent: animation,
+          curve: Curves.fastOutSlowIn,
+          reverseCurve: Curves.fastOutSlowIn.flipped)),
+      child: SizeTransition(
+        axis: Axis.vertical,
+        sizeFactor: animation,
+        child: _buildNotificationCard(index),
+      ),
+    );
+  }
+
+  /// 收缩移除
+  Widget _buildNotificationSizeOut(
+      BuildContext context, int index, Animation<double> animation) {
+    return SizeTransition(
+      axis: Axis.vertical,
+      sizeFactor: animation,
+      child: _buildNotificationCard(index),
+    );
+  }
+
+  Widget _buildNotificationCard(int index) {
+    return NotificationCard(
+      notification: notifications[index],
+      onClose: () {
+        _removeNotification(index);
+      },
+    );
+  }
+}

+ 108 - 0
lib/notification_demo/notification_card.dart

@@ -0,0 +1,108 @@
+import 'package:calendar_view/notification_demo/notification_controller.dart';
+import 'package:flutter/material.dart';
+
+/// 消息卡片
+class NotificationCard extends StatelessWidget {
+  const NotificationCard(
+      {super.key, required this.notification, required this.onClose});
+  final SystemNotification notification;
+  final VoidCallback onClose;
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      decoration: BoxDecoration(
+        color: Colors.white,
+        borderRadius: BorderRadius.circular(8),
+        boxShadow: const [
+          BoxShadow(
+            color: Colors.black12,
+            blurRadius: 4,
+            spreadRadius: 2,
+          ),
+        ],
+      ),
+      margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 8),
+      width: double.infinity,
+      child: Column(
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          Container(
+            /// 灰色下边框
+            decoration: const BoxDecoration(
+              border: Border(
+                bottom: BorderSide(
+                  color: Colors.black12,
+                  width: 1,
+                ),
+              ),
+            ),
+            padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
+            child: Row(
+              children: [
+                const Icon(
+                  Icons.notifications_none,
+                  color: Colors.blue,
+                ),
+                Text(notification.title),
+                const Spacer(),
+                InkWell(
+                    onTap: () {
+                      onClose();
+                    },
+                    child: const Icon(Icons.close)),
+              ],
+            ),
+          ),
+          Container(
+            padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
+            child: Text(
+              notification.infoTitle,
+              style: const TextStyle(
+                color: Color.fromARGB(255, 30, 30, 30),
+                fontSize: 16,
+                fontWeight: FontWeight.w600,
+              ),
+            ),
+          ),
+          ..._buildInfoContents(notification.infoItems),
+        ],
+      ),
+    );
+  }
+
+  List<Widget> _buildInfoContents(List<NotificationInfoItem> infoContents) {
+    return infoContents
+        .map(
+          (e) => Container(
+            margin: const EdgeInsets.only(bottom: 8),
+            padding: const EdgeInsets.symmetric(horizontal: 12),
+            child: Row(
+              children: [
+                Expanded(
+                  flex: 1,
+                  child: Text(
+                    e.title,
+                    style: const TextStyle(
+                        color: Color.fromARGB(255, 40, 40, 40),
+                        fontSize: 14,
+                        fontWeight: FontWeight.w600),
+                  ),
+                ),
+                Expanded(
+                  flex: 3,
+                  child: Text(
+                    e.content,
+                    style: const TextStyle(
+                        color: Color.fromARGB(255, 40, 40, 40),
+                        fontSize: 14,
+                        fontWeight: FontWeight.w500),
+                  ),
+                ),
+              ],
+            ),
+          ),
+        )
+        .toList();
+  }
+}

+ 92 - 0
lib/notification_demo/notification_controller.dart

@@ -0,0 +1,92 @@
+import 'package:calendar_view/utils/event_type.dart';
+import 'package:get/get.dart';
+
+class NotificationController extends GetxController {
+  NotificationController();
+
+  FEventHandler<SystemNotification> onReceiveNotification =
+      FEventHandler<SystemNotification>();
+
+  void handleReceiveNotification(SystemNotification notification) {
+    onReceiveNotification.emit(this, notification);
+  }
+
+  /// 构造一个假消息
+  void sendMockNotification() {
+    handleReceiveNotification(SystemNotification(
+      title: '系统通知',
+      infoTitle: '会诊将在15分钟后开始,请及时参与!',
+      infoItems: [
+        NotificationInfoItem(
+          title: '姓名',
+          content: '陈圆润',
+        ),
+        NotificationInfoItem(
+          title: '会诊时间',
+          content: '2021-11-11 11:11:11',
+        ),
+        NotificationInfoItem(
+          title: '会诊专家',
+          content: 'Albert Einstein',
+        ),
+      ],
+      type: NotificationType.notification,
+      callback: () {
+        print('点击了详情按钮');
+      },
+      callbackButtonText: '详情',
+    ));
+  }
+
+  @override
+  void onInit() {
+    super.onInit();
+
+    /// 注册通知接收器
+  }
+}
+
+///  系统通知
+class SystemNotification {
+  SystemNotification({
+    required this.title,
+    required this.infoTitle,
+    required this.infoItems,
+    required this.type,
+    this.callback,
+    this.callbackButtonText,
+  });
+
+  final String title;
+  final String infoTitle;
+  final List<NotificationInfoItem> infoItems;
+  final NotificationType type;
+  final Function? callback;
+  final String? callbackButtonText;
+}
+
+/// 通知信息字段
+class NotificationInfoItem {
+  NotificationInfoItem({
+    required this.title,
+    required this.content,
+  });
+
+  final String title;
+  final String content;
+}
+
+/// 通知类型
+enum NotificationType {
+  /// 通知
+  notification,
+
+  /// 警告
+  warning,
+
+  /// 错误
+  error,
+
+  /// 成功
+  success,
+}