import 'dart:async'; import 'dart:convert'; import 'package:dio/dio.dart'; import 'package:flutter_openim_sdk/flutter_openim_sdk.dart'; import 'package:get/get.dart'; import 'package:openim_common/openim_common.dart'; import 'package:sprintf/sprintf.dart'; import 'utils/api_service.dart'; class Apis { static Options get imTokenOptions => Options(headers: {'token': DataSp.imToken}); static Options get chatTokenOptions => Options(headers: {'token': DataSp.chatToken}); static StreamController kickoffController = StreamController.broadcast(); static void _kickoff(int? errCode) { if (errCode == 1501 || errCode == 1503 || errCode == 1504 || errCode == 1505) { kickoffController.sink.add(errCode); } } static Future login({ String? areaCode, String? phoneNumber, String? account, String? email, String? password, String? verificationCode, }) async { try { var data = await HttpUtil.post(Urls.login, data: { "areaCode": areaCode, 'account': account, 'phoneNumber': phoneNumber, 'email': email, 'password': null != password ? IMUtils.generateMD5(password) : null, 'platform': IMUtils.getPlatform(), 'verifyCode': verificationCode, }); final cert = LoginCertificate.fromJson(data!); ApiService().setToken(cert.imToken); return cert; } catch (e, _) { final t = e as (int, String?)?; if (t == null) { Logger.print('e:$e'); return Future.error(e); } final errCode = t.$1; final errMsg = t.$2; _kickoff(errCode); Logger.print('e:$errCode s:$errMsg'); return Future.error(e); } } static Future register({ required String nickname, required String password, String? faceURL, String? areaCode, String? phoneNumber, String? email, String? account, int birth = 0, int gender = 1, required String verificationCode, String? invitationCode, }) async { try { var data = await HttpUtil.post(Urls.register, data: { 'deviceID': DataSp.getDeviceID(), 'verifyCode': verificationCode, 'platform': IMUtils.getPlatform(), 'invitationCode': invitationCode, 'autoLogin': true, 'user': { "nickname": nickname, "faceURL": faceURL, 'birth': birth, 'gender': gender, 'email': email, "areaCode": areaCode, 'phoneNumber': phoneNumber, 'account': account, 'password': IMUtils.generateMD5(password), }, }); final cert = LoginCertificate.fromJson(data!); ApiService().setToken(cert.imToken); return cert; } catch (e, s) { final t = e as (int, String?); final errCode = t.$1; final errMsg = t.$2; _kickoff(errCode); Logger.print('e:$errCode s:$errMsg'); return Future.error(e); } } static Future resetPassword({ String? areaCode, String? phoneNumber, String? email, required String password, required String verificationCode, }) async { try { return HttpUtil.post( Urls.resetPwd, data: { "areaCode": areaCode, 'phoneNumber': phoneNumber, 'email': email, 'password': IMUtils.generateMD5(password), 'verifyCode': verificationCode, 'platform': IMUtils.getPlatform(), }, options: chatTokenOptions, ); } catch (e, s) { final t = e as (int, String?); final errCode = t.$1; final errMsg = t.$2; _kickoff(errCode); Logger.print('e:$errCode s:$errMsg'); } } static Future changePassword({ required String userID, required String currentPassword, required String newPassword, }) async { try { await HttpUtil.post( Urls.changePwd, data: { "userID": userID, 'currentPassword': IMUtils.generateMD5(currentPassword), 'newPassword': IMUtils.generateMD5(newPassword), 'platform': IMUtils.getPlatform(), }, options: chatTokenOptions, ); return true; } catch (e, s) { final t = e as (int, String?); final errCode = t.$1; final errMsg = t.$2; _kickoff(errCode); Logger.print('e:$errCode s:$errMsg'); return false; } } static Future changePasswordOfB({ required String newPassword, }) async { try { await HttpUtil.post( Urls.resetPwd, data: { 'password': IMUtils.generateMD5(newPassword), 'platform': IMUtils.getPlatform(), }, options: chatTokenOptions, ); return true; } catch (e) { return false; } } static Future updateUserInfo({ required String userID, String? account, String? phoneNumber, String? areaCode, String? email, String? nickname, String? faceURL, int? gender, int? birth, int? level, int? allowAddFriend, int? allowBeep, int? allowVibration, }) async { // 原 chat `/user/update` 已随 :10008 下线。OpenIM 只同步昵称/头像; // 邮箱、性别、生日等业务字段由调用方更新本地状态,不打账号服务。 if (userID.isEmpty) return {}; if (nickname != null || faceURL != null) { await OpenIM.iMManager.userManager.setSelfInfo( nickname: nickname, faceURL: faceURL, ); } return {}; } static Future> searchFriendInfo( String keyword, { int pageNumber = 1, int showNumber = 10, }) async { try { final data = await HttpUtil.post( Urls.searchFriendInfo, data: { 'pagination': {'pageNumber': pageNumber, 'showNumber': showNumber}, 'keyword': keyword, }, options: chatTokenOptions, ); if (data['users'] is List) { return (data['users'] as List) .map((e) => FriendInfo.fromJson(e)) .toList(); } return []; } catch (e, s) { final t = e as (int, String?); final errCode = t.$1; final errMsg = t.$2; _kickoff(errCode); Logger.print('e:$errCode s:$errMsg'); return []; } } static Future?> getUserFullInfo({ int pageNumber = 0, int showNumber = 10, required List userIDList, }) async { if (userIDList.isEmpty) return []; try { final users = await OpenIM.iMManager.userManager.getUsersInfo( userIDList: userIDList, ); return users .map((e) => UserFullInfoMapper.fromImJson(e.toJson())) .toList(); } catch (e, s) { Logger.print('getUserFullInfo e:$e s:$s'); return []; } } static Future?> searchUserFullInfo({ required String content, int pageNumber = 1, int showNumber = 10, }) async { final keyword = content.trim(); if (keyword.isEmpty) return []; if (pageNumber > 1) return []; return getUserFullInfo(userIDList: [keyword], showNumber: showNumber); } static Future queryMyFullInfo() async { try { final user = await OpenIM.iMManager.userManager.getSelfUserInfo(); return UserFullInfoMapper.fromImJson(user.toJson()); } catch (e, s) { Logger.print('queryMyFullInfo e:$e s:$s'); return null; } } static Future requestVerificationCode({ String? areaCode, String? phoneNumber, String? email, required int usedFor, String? invitationCode, }) async { return HttpUtil.post( Urls.getVerificationCode, data: { "areaCode": areaCode, "phoneNumber": phoneNumber, "email": email, 'usedFor': usedFor, 'invitationCode': invitationCode }, ).then((value) { IMViews.showToast(StrRes.sentSuccessfully); return true; }).catchError((e, s) { Logger.print('e:$e s:$s'); return false; }); } static Future getTokenForRTC( String roomID, String userID) async { return HttpUtil.post( Urls.getTokenForRTC, data: { "room": roomID, "identity": userID, }, options: chatTokenOptions, ).then((value) { final signaling = SignalingCertificate.fromJson(value)..roomID = roomID; return signaling; }).catchError((e, s) { Logger.print('e:$e s:$s'); }); } static Future checkVerificationCode({ String? areaCode, String? phoneNumber, String? email, required String verificationCode, required int usedFor, String? invitationCode, }) { return HttpUtil.post( Urls.checkVerificationCode, data: { "phoneNumber": phoneNumber, "areaCode": areaCode, "email": email, "verifyCode": verificationCode, "usedFor": usedFor, 'invitationCode': invitationCode }, ); } static Future checkUpgradeV2() { return dio.post>( 'https://www.pgyer.com/apiv2/app/check', options: Options( contentType: 'application/x-www-form-urlencoded', ), data: { '_api_key': '', 'appKey': '', }, ).then((resp) { Map map = resp.data!; if (map['code'] == 0) { return UpgradeInfoV2.fromJson(map['data']); } return Future.error(map); }); } static Future> getClientConfig() async { return { 'discoverPageURL': Config.discoverPageURL, 'allowSendMsgNotFriend': Config.allowSendMsgNotFriend }; } static void _catchError(Object e, StackTrace s, {bool forceBack = true}) { if (e is ApiException) { var msg = '${e.code}'.tr; if (msg.isEmpty || e.code.toString() == msg) { msg = e.message ?? 'Unkonw error'; } else if (e.code == 1004) { msg = sprintf(msg, [StrRes.meeting]); } IMViews.showToast(msg); if ((e.code == 10010 || e.code == 10002) && forceBack) { DataSp.removeLoginCertificate(); Get.offAllNamed('/login'); } } else { IMViews.showToast(e.toString()); } } }