import 'package:device_info_plus/device_info_plus.dart'; import 'package:flutter/foundation.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:url_launcher/url_launcher.dart'; import '../../../common/services/device_header_service.dart'; import '../../auth/data/auth_models.dart'; class FeedbackEmailService { const FeedbackEmailService._(); static const recipient = 'business@yqzhice.top'; static const productName = '金值'; static Future send(AuthState? authState) async { final email = await _buildEmail(authState); final uri = composeMailtoUri( recipient: email.recipient, subject: email.subject, body: email.body, ); try { final launched = await launchUrl( uri, mode: LaunchMode.externalApplication, ); if (!launched) throw const FeedbackEmailUnavailableException(); } catch (_) { throw const FeedbackEmailUnavailableException(); } } @visibleForTesting static Uri composeMailtoUri({ required String recipient, required String subject, required String body, }) => Uri( scheme: 'mailto', path: recipient, query: _encodeQueryParameters({'subject': subject, 'body': body}), ); static String _encodeQueryParameters( Map parameters, ) => parameters.entries .map( (entry) => '${Uri.encodeComponent(entry.key)}=${Uri.encodeComponent(entry.value)}', ) .join('&'); static Future<_FeedbackEmail> _buildEmail(AuthState? authState) async { final packageInfo = await PackageInfo.fromPlatform(); final device = await _loadDeviceInfo(); try { await DeviceHeaderService.to.ensureInitialized(); } catch (_) {} final headers = DeviceHeaderService.to.commonHeaders(); final loggedIn = authState is LoggedInAuthState ? authState : null; final version = '${packageInfo.version}+${packageInfo.buildNumber}'; final diagnostics = [ 'App version: $version', 'Channel: ${headers['User-Channel'] ?? ''}', 'OS version: ${device.osVersion}', 'Device manufacturer: ${device.manufacturer}', 'Device model: ${device.model}', 'Login type: ${loggedIn == null ? 'guest' : 'phone'}', 'Phone: ${loggedIn?.user.phone ?? ''}', ].join('\n'); return _FeedbackEmail( recipient: recipient, subject: '$productName反馈[$version]-[${device.manufacturer}]-[${device.osVersion}]', body: [ '$productName团队你好,', '请描述你的问题,可附上截图或视频:', '', '', '----', diagnostics, ].join('\n'), ); } static Future<_FeedbackDeviceInfo> _loadDeviceInfo() async { final plugin = DeviceInfoPlugin(); try { if (kIsWeb) { final info = await plugin.webBrowserInfo; return _FeedbackDeviceInfo( osVersion: info.platform ?? 'web', manufacturer: info.browserName.name, model: info.userAgent ?? '', ); } if (defaultTargetPlatform == TargetPlatform.android) { final info = await plugin.androidInfo; return _FeedbackDeviceInfo( osVersion: info.version.release, manufacturer: info.manufacturer, model: info.model, ); } if (defaultTargetPlatform == TargetPlatform.iOS) { final info = await plugin.iosInfo; return _FeedbackDeviceInfo( osVersion: info.systemVersion, manufacturer: 'Apple', model: info.utsname.machine, ); } return const _FeedbackDeviceInfo( osVersion: '', manufacturer: '', model: '', ); } catch (_) { return const _FeedbackDeviceInfo( osVersion: '', manufacturer: '', model: '', ); } } } class FeedbackEmailUnavailableException implements Exception { const FeedbackEmailUnavailableException(); } class _FeedbackEmail { const _FeedbackEmail({ required this.recipient, required this.subject, required this.body, }); final String recipient; final String subject; final String body; } class _FeedbackDeviceInfo { const _FeedbackDeviceInfo({ required this.osVersion, required this.manufacturer, required this.model, }); final String osVersion; final String manufacturer; final String model; }