import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:broadcast/broadcast.dart'; import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart' hide Message; import 'package:get_it/get_it.dart'; import 'package:getuiflut/getuiflut.dart'; import 'package:provider/provider.dart'; import 'package:rxdart/subjects.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:sport/application.dart'; import 'package:sport/bean/game.dart'; import 'package:sport/bean/message.dart'; import 'package:sport/bean/user_info.dart'; import 'package:sport/db/message_db.dart'; import 'package:sport/pages/game/game_detail.dart'; import 'package:sport/pages/social/chat_page.dart'; import 'package:sport/provider/game_model.dart'; import 'package:sport/provider/user_model.dart'; import 'package:sport/router/navigator_util.dart'; import 'package:sport/services/api/inject_api.dart'; import 'package:sport/services/api/request.dart'; import 'package:sport/services/api/resp.dart'; import 'package:sport/services/api/rest_client.dart'; import 'package:sport/widgets/button_primary.dart'; import 'package:sport/widgets/image.dart'; final BehaviorSubject didReceiveLocalNotificationSubject = BehaviorSubject(); final BehaviorSubject selectNotificationSubject = BehaviorSubject(); const MethodChannel platform = MethodChannel('dexterx.dev/flutter_local_notifications_example'); class ReceivedNotification { ReceivedNotification({ required this.id, required this.title, required this.body, required this.payload, }); final int id; final String? title; final String? body; final String? payload; } class MessageModel extends ChangeNotifier with InjectApi { // Message _message; int? _curId; AppLifecycleState? state; String? selfId; final StreamController _queryController = StreamController.broadcast(); Stream get queryStream => _queryController.stream; ///事件订阅对象 StreamSubscription? periodicSubscription, countPeriodicSubscription; final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); push(BuildContext context) async { var user = Provider.of(context, listen: false); var userId = user.user.id; print("flutter push user $userId"); if (userId == 0) return; final AndroidInitializationSettings initializationSettingsAndroid = AndroidInitializationSettings('app_icon'); final IOSInitializationSettings initializationSettingsIOS = IOSInitializationSettings( requestAlertPermission: false, requestBadgePermission: false, requestSoundPermission: false, onDidReceiveLocalNotification: (int id, String? title, String? body, String? payload) async { didReceiveLocalNotificationSubject.add(ReceivedNotification(id: id, title: title, body: body, payload: payload)); }); final InitializationSettings initializationSettings = InitializationSettings(android: initializationSettingsAndroid, iOS: initializationSettingsIOS); await flutterLocalNotificationsPlugin.initialize(initializationSettings, onSelectNotification: (String? payload) async { if (payload != null) { debugPrint('notification payload: $payload'); UserInfo? info = (await api.getUserInfo("$payload")).data; if (info != null) await NavigatorUtil.goPage( context, (context) => ChatPage( info, fetch: true, )); } selectNotificationSubject.add(payload); }); // // if (Platform.isAndroid) { // await FlutterPluginMipush.init(appId: "2882303761520111715", appKey: "5722011155715"); // } else if (Platform.isIOS) { // await FlutterPluginMipush.init(appId: "2882303761520111481", appKey: "5942011177481·"); // } else { // return; // } // // await FlutterPluginMipush.setAlias(alias: "$userId", category: "app"); // FlutterPluginMipush.stream.listen((event) { // print("FlutterPluginMipush listen $event"); // Map extra = json.decode(event); // _addPushMessage(context, extra); // }); print("flutter initGetuiSdk"); var getuiflut = Getuiflut(); getuiflut.addEventHandler( // 注册收到 cid 的回调 onReceiveClientId: (String message) async { print("flutter onReceiveClientId: $message"); getuiflut.bindAlias("$userId", "app"); }, // 注册 DeviceToken 回调 onRegisterDeviceToken: (String message) async { print("flutter onRegisterDeviceToken: $message"); }, // SDK收到透传消息回调 onReceivePayload: (Map message) async { print("flutter onReceivePayload: $message"); if (message.containsKey("payloadMsg")) { try { _addPushMessage(context, json.decode(message["payloadMsg"])); } catch (e) { print(e); } } }, // 点击通知回调 onReceiveNotificationResponse: (Map message) async { print("flutter onReceiveNotificationResponse: $message"); }, // APPLink中携带的透传payload信息 onAppLinkPayload: (String message) async {}, //通知服务开启\关闭回调 onPushModeResult: (Map message) async { print("flutter onPushModeResult: $message"); }, // SetTag回调 onSetTagResult: (Map message) async { print("flutter onSetTagResult: $message"); }, //设置别名回调 onAliasResult: (Map message) async { print("flutter onAliasResult: $message"); }, //查询别名回调 onQueryTagResult: (Map message) async { print("flutter onQueryTagResult: $message"); }, //APNs通知即将展示回调 onWillPresentNotification: (Map message) async { print("flutter onWillPresentNotification: $message"); }, //APNs通知设置跳转回调 onOpenSettingsForNotification: (Map message) async { print("flutter onOpenSettingsForNotification: $message"); }, onReceiveMessageData: (Map event) async { print("flutter onReceiveMessageData: $event"); if (event.containsKey("payload")) { try { _addPushMessage(context, json.decode(event["payload"])); } catch (e) { print(e); } } }, onNotificationMessageClicked: (Map event) async { print("flutter onNotificationMessageClicked: $event"); if (event.containsKey("payload")) { try { _addPushMessage(context, json.decode(event["payload"])); } catch (e) { print(e); } } }, onNotificationMessageArrived: (Map event) async { print("flutter onNotificationMessageArrived: $event"); }, // onGrantAuthorization: (String res) async { }, // onTransmitUserMessageReceive: (Map event) async{ }, ); if (Platform.isAndroid) { try { await Getuiflut.initGetuiSdk; } catch (e) { print(e); print("flutter Getuiflut: $e"); } } else if (Platform.isIOS) { getuiflut.startSdk(appId: "Rvnote7osU9Ntxk4tpEP46", appKey: "9bHdNmOfPu5KXKAVKKXUv4", appSecret: "aMP4ifBDUJAzvL7KUe2M33"); } } Future _showNotification(ReceivedNotification notification) async { final AndroidNotificationDetails androidPlatformChannelSpecifics = AndroidNotificationDetails('101', '趣动', importance: Importance.defaultImportance, priority: Priority.defaultPriority, ticker: '${DateTime.now().millisecondsSinceEpoch}'); final NotificationDetails platformChannelSpecifics = NotificationDetails(android: androidPlatformChannelSpecifics); await flutterLocalNotificationsPlugin.show(notification.id, '${notification.title}', '${notification.body}', platformChannelSpecifics, payload: '${notification.payload}'); } Future getGame(BuildContext context, int id) async { GameModel gameModel = GetIt.I(); GameInfoData? game = await gameModel.getGame(id); return game; } _addPushMessage(BuildContext context, Map extra) async { print("_addPushMessage: $extra"); GameInfoData? game = await getGame(context, extra['game_id']); if (game == null) return; RespData user = await GetIt.I().getUserInfo("${extra['from_id']}"); UserInfo? userInfo = user.data; if (userInfo == null) return; Map args = { 'invite': {"info": "${extra['invite_info']}", "user": userInfo.toJsonSimple(), "game_id": "${game.id}", "ts": DateTime.now().millisecondsSinceEpoch}, }; print("jpush broadcast: $args"); Broadcast.broadcast("SHOE.SDK.GAME_INVITE", args: args); if (state == AppLifecycleState.inactive || state == AppLifecycleState.paused) { _showNotification(ReceivedNotification(id: 1, title: "趣动", body: "${userInfo.name}邀请您玩${game.name}", payload: "${userInfo.id}")); // jpush.sendLocalNotification(LocalNotification(buildId: 1, id: 1, title: "趣动", content: "${userInfo.name}邀请您玩${game.name}", fireTime: DateTime.now())); } else { bool _showing = true; OverlayEntry? entry; entry = OverlayEntry(builder: (context) { return Positioned( //top值,可以改变这个值来改变toast在屏幕中的位置 top: 20, child: Material( color: Color(0x00000000), child: SafeArea( child: Container( width: MediaQuery.of(context).size.width, alignment: Alignment.center, //居中 child: AnimatedOpacity( //目标透明度 opacity: _showing ? 1.0 : 0.0, //执行时间 duration: Duration(milliseconds: 1000), child: Container( padding: EdgeInsets.all(12.0), width: double.infinity, margin: EdgeInsets.symmetric(horizontal: 12.0), decoration: BoxDecoration(borderRadius: BorderRadius.circular(10.0), color: Color(0xff241D19).withOpacity(.8)), child: Row( children: [ CircleAvatar( backgroundColor: Colors.black26, radius: 22, backgroundImage: userAvatarProvider("${userInfo.avatar}"), ), const SizedBox( width: 12, ), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "${userInfo.name}", style: TextStyle(color: Colors.white, fontSize: 14), ), SizedBox( height: 5, ), Row( children: [ Text( "邀请您玩", style: TextStyle(color: Colors.white, fontSize: 12), ), Text( "${game.name}", style: TextStyle(color: Theme.of(context).accentColor, fontSize: 12), ), ], ) ], ), ), const SizedBox( width: 6, ), GestureDetector( onTap: () { if (entry != null) { entry!.remove(); } entry = null; }, child: Container( child: Center( child: Text( "取消", style: TextStyle(color: Colors.white, fontSize: 12), )), height: 30.0, width: 60.0, decoration: BoxDecoration( border: Border.all( color: Colors.white, width: 1, ), borderRadius: BorderRadius.circular(50)), ), ), const SizedBox( width: 6, ), PrimaryButton( callback: () { if (entry != null) { _showing = false; if (!_showing) { entry!.remove(); } } entry = null; startGame(context, game, invite: "${extra['invite_info']}", user: userInfo, skipGuide: true); }, content: "继续", height: 30.0, width: 60.0, fontSize: 12, ) ], ), ), )), ), )); }); if (entry != null) Overlay.of(context)?.insert(entry!); await Future.delayed(Duration(milliseconds: 5000)); if (entry != null) { _showing = false; //重新绘制UI,类似setState entry!.markNeedsBuild(); //等待动画执行 await Future.delayed(Duration(milliseconds: 1000)); if (!_showing) { entry!.remove(); } } entry = null; } } loop(BuildContext context) async { close(); if (inProduction) { if (openSocial()) periodicSubscription = Stream.periodic(Duration(seconds: 10)).listen((event) { if (state == AppLifecycleState.inactive || state == AppLifecycleState.paused) return; loopMessage(context); }); countPeriodicSubscription = Stream.periodic(Duration(seconds: 60)).listen((event) { _loopCount(); }); selfId = "${Provider.of(context, listen: false).user.id}"; _loopCount(); } } loopMessage(BuildContext context) async { Message? data; SharedPreferences prefs = await SharedPreferences.getInstance(); String? token = prefs.getString("token"); if (token == null || token.isEmpty == true) return; if (_curId != null) { data = (await api.getMessageForPoll(curId: _curId)).data; } else { data = (await api.getMessageForPoll()).data; } if (data == null) return; // curId 这里一定是接口返回的 本地存 sqlite的 curId 全部都是 0 _curId = data.curId; List messages = data.messages ?? []; // 没有新消息还处理流程吗? // if(_messages.length == 0) // return // var list = await MessageDB().findAll(); // 清空数字 // print("[list]:$list--------------------------"); // var userList = await MessageDB().findAllUser(); // print("[list]:$userList--------------------------"); // MessageDB().deleteTable(); // // 这里本来是做了去重操作的 现在不用了 ... // if (_messages.length > 0) { // var list = await MessageDB().findLatest(); // print(list); // if (list.length != 0) { // int lastCurId = list[0]["curId"]; // print('[lastCurId]:$lastCurId-------------------------'); // // 可能会重复插入...; // if (lastCurId != _curId) { // add(data.messages, _curId); // } // } else { //// add(data.messages, _curId); // } // } int me = Provider.of(context, listen: false).user.id; _add(me, messages); } add(BuildContext context, List messages) async { int me = Provider.of(context, listen: false).user.id; _add(me, messages); } _add(int me, List messages) async { if (messages.isEmpty == true) return; List> _items = []; int messageCount = 0; for (MessageInstance _instance in messages) { bool isMe = me == _instance.fromUser?.id; MessageUser? other = isMe ? _instance.toUser : _instance.fromUser; if (other == null) continue; var list = await MessageDB().findHasUserId(me, other.id!); int chatId = 0; if (list.length == 0) { chatId = await MessageDB().createChatUser(me, other); } else { var dbUser = list[0]; chatId = dbUser['id']; if (other.name != dbUser['name'] || other.avatar != dbUser['avatar']) { MessageDB().updateChatUser(chatId, other); } } Map map = _instance.toDBJson(); map['chat_id'] = chatId; // 插进去是 0: 已读, 1: 未读 map['status'] = isMe ? 0 : 1; _items.add(map); messageCount += isMe ? 0 : 1; } // print("1111111111111111111 add message $_items"); await MessageDB().insertAll(_items); notifierMessage.value = notifierMessage.value + messageCount; if (messages.isNotEmpty == true) _queryController.add(messages.length); } close() { ///关闭 periodicSubscription?.cancel(); countPeriodicSubscription?.cancel(); // _queryController.close(); } ValueNotifier notifierComment = ValueNotifier(0); ValueNotifier notifierLike = ValueNotifier(0); ValueNotifier notifierSocial = ValueNotifier(0); ValueNotifier notifierMessage = ValueNotifier(0); ValueNotifier notifierFriendFansList = ValueNotifier(0); ValueNotifier notifierFriendFollowList = ValueNotifier(0); ValueNotifier notifierFriend = ValueNotifier(0); ValueNotifier notifierSocialTotal = ValueNotifier(0); // // getSocialCount() async { // int count = 0; // try { // int _count = (await api.getNoticeCount("comment", "0")).data ?? 0; // notifierComment.value = _count; // count += _count; // } catch (e) { // print(e); // } // try { // int _count = (await api.getNoticeCount("like", "0")).data ?? 0; // notifierLike.value = _count; // count += _count; // } catch (e) { // print(e); // } // // List result = messag // // notifierSocial.value = count + unRead; // } // // getFriendCount() async { // int count = 0; // // try { // // FriendList? list = (await api.userFollowList(limit: 1)).data; // // int _count = 0; // // list?.list?.forEach((element) { // // if(element.isIgnore == 0 && element.isFriends == "0") // // _count += 1; // // }); // // notifierFriendFollowList.value = _count; // // count += _count; // // } catch (e) { // // print(e); // // } // try { // // FriendList? list = (await api.userFansList(limit: 1)).data; // // int _count = 0; // // list?.list?.forEach((element) { // // if(element.isIgnore == 0 && element.isFriends == "0") // // _count += 1; // // }); // int _count = (await api.userFansList(limit: 1)).data?.noIgnoreCount ?? 0; // notifierFriendFansList.value = _count; // count += _count; // } catch (e) { // print(e); // } // notifierFriend.value = count; // } void getCount() async { List result = await mergeMessageCount(); // int count = result.fold(0, (previousValue, element) => previousValue + element); notifierLike.value = result[0]; notifierComment.value = result[1]; notifierFriendFansList.value = result[2]; int unRead = 0; if (selfId != null) { var unReadList = await MessageDB().getMessageUnRead(selfId!); unRead = unReadList.fold(0, (previousValue, element) => previousValue + (element["cout"] as int)); notifierMessage.value = unRead; } notifierSocial.value = result[0] + result[1] + unRead; notifierFriend.value = result[2]; } void _loopCount() { SharedPreferences.getInstance().then((value) { if (value.containsKey("token")) { getCount(); } }); } void init() { notifierSocial.addListener(() { notifierSocialTotal.value = notifierSocial.value + notifierFriend.value; }); notifierFriend.addListener(() { notifierSocialTotal.value = notifierSocial.value + notifierFriend.value; }); notifierMessage.addListener(() { notifierSocial.value = notifierComment.value + notifierLike.value + notifierMessage.value; notifierSocialTotal.value = notifierSocial.value + notifierFriend.value; }); if (inProduction && openSocial()) { _loopCount(); } Connectivity().onConnectivityChanged.listen((ConnectivityResult result) { connectivityResult = result; }); } }