From 5b0b5b862eda0e84f9b867927dbac91cd4507048 Mon Sep 17 00:00:00 2001 From: NIGGER SLAYER Date: Mon, 20 Apr 2026 20:15:44 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AD=BE=E5=88=B0=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/main.dart | 5 - lib/modules/index/index_page.dart | 51 +- .../recharge/mifa_pay_webview_page.dart | 120 - .../recharge_method_bottom_sheet.dart | 463 ---- .../wallet/recharge/recharge_page.dart | 418 +-- lib/services/payment/mifa_pay_manager.dart | 451 ---- .../models/res/sc_mifa_pay_res.dart | 135 + .../models/res/sc_sign_in_reward_res.dart | 211 ++ .../repositories/config_repository.dart | 3 + .../repositories/user_repository.dart | 41 +- .../sc_config_repository_imp.dart | 13 + .../repositories/sc_user_repository_impl.dart | 2404 +++++++++-------- .../daily_sign_in/daily_sign_in_dialog.dart | 164 +- .../example/devtools_options.yaml | 3 + 需求进度.md | 5 +- 15 files changed, 1811 insertions(+), 2676 deletions(-) delete mode 100644 lib/modules/wallet/recharge/mifa_pay_webview_page.dart delete mode 100644 lib/modules/wallet/recharge/recharge_method_bottom_sheet.dart delete mode 100644 lib/services/payment/mifa_pay_manager.dart create mode 100644 lib/shared/business_logic/models/res/sc_sign_in_reward_res.dart create mode 100644 local_packages/flutter_foreground_task-9.1.0/example/devtools_options.yaml diff --git a/lib/main.dart b/lib/main.dart index 1e244e7..142b1c6 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -34,7 +34,6 @@ import 'services/auth/authentication_manager.dart'; import 'services/gift/gift_animation_manager.dart'; import 'services/gift/gift_system_manager.dart'; import 'services/payment/google_payment_manager.dart'; -import 'services/payment/mifa_pay_manager.dart'; import 'services/localization/localization_manager.dart'; import 'services/room/rc_room_manager.dart'; import 'services/audio/rtc_manager.dart'; @@ -262,10 +261,6 @@ class RootAppWithProviders extends StatelessWidget { lazy: true, create: (context) => IOSPaymentProcessor(), ), - ChangeNotifierProvider( - lazy: true, - create: (context) => MiFaPayManager(), - ), ChangeNotifierProvider( lazy: true, create: (context) => ShopManager(), diff --git a/lib/modules/index/index_page.dart b/lib/modules/index/index_page.dart index 674956c..e83a6c0 100644 --- a/lib/modules/index/index_page.dart +++ b/lib/modules/index/index_page.dart @@ -4,7 +4,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:yumi/app_localizations.dart'; import 'package:yumi/app/constants/sc_global_config.dart'; -import 'package:yumi/shared/business_logic/models/res/sc_sign_in_res.dart'; import 'package:yumi/shared/data_sources/sources/local/floating_screen_manager.dart'; import 'package:yumi/modules/home/index_home_page.dart'; import 'package:yumi/modules/chat/message/sc_message_page.dart'; @@ -318,6 +317,7 @@ class _SCIndexPageState extends State { return; } _hasShownEntryDialogs = true; + debugPrint('[SignInReward][Home] start entry dialog flow'); await _waitForRegisterRewardSocketIfNeeded(); if (!mounted) { @@ -330,9 +330,18 @@ class _SCIndexPageState extends State { } final dialogData = await _loadDailySignInDialogData(); - if (!mounted) { + if (!mounted || dialogData == null) { + debugPrint( + '[SignInReward][Home] skip daily sign-in dialog reason=no-data', + ); return; } + debugPrint( + '[SignInReward][Home] show daily sign-in dialog ' + 'checkedToday=${dialogData.checkedToday} ' + 'currentDay=${dialogData.currentItem?.day ?? 0} ' + 'items=${dialogData.items.length}', + ); _isShowingDailySignInDialog = true; await DailySignInDialog.show(context, data: dialogData); _isShowingDailySignInDialog = false; @@ -401,23 +410,33 @@ class _SCIndexPageState extends State { } } - Future _loadDailySignInDialogData() async { - DailySignInDialogData dialogData; + Future _loadDailySignInDialogData() async { try { - final result = await Future.wait([ - SCAccountRepository().checkInToday(), - SCAccountRepository().sginListAward(), - ]); - final checkedToday = result[0] as bool; - final signInRes = result[1] as SCSignInRes; - dialogData = DailySignInDialogData.fromLegacy( - signInRes: signInRes, - checkedToday: checkedToday, + debugPrint('[SignInReward][Home] loading status'); + final statusRes = await SCAccountRepository().signInRewardStatus(); + if (!statusRes.canShowDialog) { + debugPrint( + '[SignInReward][Home] dialog disabled ' + 'configured=${statusRes.configured} ' + 'enabled=${statusRes.enabled} ' + 'available=${statusRes.available} ' + 'signedToday=${statusRes.signedToday} ' + 'days=${statusRes.days.length}', + ); + return null; + } + final dialogData = DailySignInDialogData.fromStatus(statusRes: statusRes); + debugPrint( + '[SignInReward][Home] mapped dialog data ' + 'checkedToday=${dialogData.checkedToday} ' + 'currentDay=${dialogData.currentItem?.day ?? 0} ' + 'days=${dialogData.items.length}', ); - } catch (_) { - dialogData = DailySignInDialogData.mock(); + return dialogData; + } catch (error) { + debugPrint('[SignInReward][Home] load status failed error=$error'); + return null; } - return dialogData; } Widget _buildBottomTabIcon({ diff --git a/lib/modules/wallet/recharge/mifa_pay_webview_page.dart b/lib/modules/wallet/recharge/mifa_pay_webview_page.dart deleted file mode 100644 index ffff7f1..0000000 --- a/lib/modules/wallet/recharge/mifa_pay_webview_page.dart +++ /dev/null @@ -1,120 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:yumi/shared/tools/sc_url_launcher_utils.dart'; -import 'package:yumi/ui_kit/components/appbar/socialchat_appbar.dart'; -import 'package:webview_flutter/webview_flutter.dart'; - -class MiFaPayWebViewPage extends StatefulWidget { - const MiFaPayWebViewPage({ - super.key, - required this.requestUrl, - this.title = 'MiFaPay', - }); - - final String requestUrl; - final String title; - - @override - State createState() => _MiFaPayWebViewPageState(); -} - -class _MiFaPayWebViewPageState extends State { - late final WebViewController _controller; - - bool _isLoading = true; - double _progress = 0; - - @override - void initState() { - super.initState(); - _controller = - WebViewController() - ..setJavaScriptMode(JavaScriptMode.unrestricted) - ..setNavigationDelegate( - NavigationDelegate( - onNavigationRequest: (NavigationRequest request) async { - if (!SCUrlLauncherUtils.shouldOpenExternally(request.url)) { - return NavigationDecision.navigate; - } - - final bool launched = await SCUrlLauncherUtils.launchExternal( - request.url, - ); - if (launched) { - return NavigationDecision.prevent; - } - - return SCUrlLauncherUtils.isHttpUrl(request.url) - ? NavigationDecision.navigate - : NavigationDecision.prevent; - }, - onProgress: (int progress) { - _updateState(() { - _progress = progress / 100; - }); - }, - onPageStarted: (_) { - _updateState(() { - _isLoading = true; - }); - }, - onPageFinished: (_) { - _updateState(() { - _isLoading = false; - _progress = 1; - }); - }, - onWebResourceError: (_) { - _updateState(() { - _isLoading = false; - }); - }, - ), - ) - ..loadRequest(Uri.parse(widget.requestUrl)); - } - - @override - void dispose() { - super.dispose(); - } - - void _updateState(VoidCallback action) { - if (!mounted) { - return; - } - setState(action); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Colors.white, - appBar: SocialChatStandardAppBar( - title: widget.title, - actions: const [], - backgroundColor: Colors.white, - backButtonColor: Colors.black, - gradient: const LinearGradient( - colors: [Colors.white, Colors.white], - ), - ), - body: Stack( - children: [ - WebViewWidget(controller: _controller), - if (_isLoading || _progress < 1) - Positioned( - top: 0, - left: 0, - right: 0, - child: LinearProgressIndicator( - value: _progress > 0 && _progress < 1 ? _progress : null, - minHeight: 2, - color: const Color(0xff18F2B1), - backgroundColor: const Color(0xffEDEDED), - ), - ), - ], - ), - ); - } -} diff --git a/lib/modules/wallet/recharge/recharge_method_bottom_sheet.dart b/lib/modules/wallet/recharge/recharge_method_bottom_sheet.dart deleted file mode 100644 index 3cb67a1..0000000 --- a/lib/modules/wallet/recharge/recharge_method_bottom_sheet.dart +++ /dev/null @@ -1,463 +0,0 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:yumi/app/constants/sc_global_config.dart'; -import 'package:yumi/ui_kit/components/sc_debounce_widget.dart'; -import 'package:yumi/ui_kit/theme/socialchat_theme.dart'; - -enum RechargeMethodType { miFaPay, nativeStore } - -class RechargeMethodOption { - const RechargeMethodOption({ - required this.type, - required this.title, - this.assetIconPath, - this.iconData, - }); - - final RechargeMethodType type; - final String title; - final String? assetIconPath; - final IconData? iconData; -} - -class RechargePackageOption { - const RechargePackageOption({ - required this.id, - required this.coins, - required this.bonusCoins, - required this.priceLabel, - required this.badge, - }); - - final String id; - final int coins; - final int bonusCoins; - final String priceLabel; - final String badge; -} - -class RechargeChannelOption { - const RechargeChannelOption({ - required this.code, - required this.name, - this.typeLabel = '', - }); - - final String code; - final String name; - final String typeLabel; -} - -class RechargeMethodBottomSheet extends StatefulWidget { - const RechargeMethodBottomSheet({ - super.key, - required this.method, - required this.packages, - required this.channels, - required this.onConfirm, - this.initialPackageId, - this.initialChannelCode, - }); - - final RechargeMethodOption method; - final List packages; - final List channels; - final void Function( - RechargePackageOption package, - RechargeChannelOption channel, - ) - onConfirm; - final String? initialPackageId; - final String? initialChannelCode; - - @override - State createState() => - _RechargeMethodBottomSheetState(); -} - -class _RechargeMethodBottomSheetState extends State { - late String _selectedPackageId; - late String _selectedChannelCode; - - @override - void initState() { - super.initState(); - _selectedPackageId = - widget.packages.isEmpty - ? '' - : widget.initialPackageId ?? widget.packages.first.id; - _selectedChannelCode = - widget.channels.isEmpty - ? '' - : widget.initialChannelCode ?? widget.channels.first.code; - } - - @override - Widget build(BuildContext context) { - final bool canConfirm = - widget.packages.isNotEmpty && - widget.channels.isNotEmpty && - _selectedPackageId.isNotEmpty && - _selectedChannelCode.isNotEmpty; - - return SafeArea( - top: false, - child: Container( - width: ScreenUtil().screenWidth, - height: MediaQuery.of(context).size.height * 0.72, - padding: EdgeInsets.fromLTRB(14.w, 14.w, 14.w, 14.w), - decoration: BoxDecoration( - color: const Color(0xff03523a), - borderRadius: BorderRadius.only( - topLeft: Radius.circular(14.w), - topRight: Radius.circular(14.w), - ), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Expanded( - child: Text( - widget.method.title, - style: TextStyle( - fontSize: 18.sp, - color: Colors.white, - fontWeight: FontWeight.w700, - ), - ), - ), - SCDebounceWidget( - onTap: () => Navigator.of(context).pop(), - child: Icon( - CupertinoIcons.clear_thick_circled, - size: 22.w, - color: Colors.white.withValues(alpha: 0.86), - ), - ), - ], - ), - SizedBox(height: 6.w), - Text( - 'Select amount', - style: TextStyle( - fontSize: 12.sp, - color: Colors.white.withValues(alpha: 0.68), - fontWeight: FontWeight.w500, - ), - ), - SizedBox(height: 16.w), - Expanded( - child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (widget.packages.isEmpty) - _buildEmptyHint('MiFaPay products are loading') - else - GridView.builder( - itemCount: widget.packages.length, - padding: EdgeInsets.zero, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 3, - mainAxisSpacing: 10.w, - crossAxisSpacing: 10.w, - mainAxisExtent: 136.w, - ), - itemBuilder: (BuildContext context, int index) { - final RechargePackageOption item = - widget.packages[index]; - final bool isSelected = item.id == _selectedPackageId; - return _buildPackageCard(item, index, isSelected); - }, - ), - SizedBox(height: 16.w), - Text( - 'Payment channel', - style: TextStyle( - fontSize: 12.sp, - color: Colors.white.withValues(alpha: 0.68), - fontWeight: FontWeight.w500, - ), - ), - SizedBox(height: 10.w), - if (widget.channels.isEmpty) - _buildEmptyHint('No channel available') - else - Wrap( - spacing: 10.w, - runSpacing: 10.w, - children: widget.channels - .map(_buildChannelChip) - .toList(growable: false), - ), - ], - ), - ), - ), - SizedBox(height: 8.w), - SCDebounceWidget( - onTap: () { - if (!canConfirm) { - return; - } - _confirmSelection(); - }, - child: Container( - width: double.infinity, - height: 42.w, - alignment: Alignment.center, - decoration: BoxDecoration( - color: - canConfirm - ? SCGlobalConfig.businessLogicStrategy - .getRechargePageButtonBackgroundColor() - : Colors.white.withValues(alpha: 0.18), - borderRadius: BorderRadius.circular(10.w), - ), - child: Text( - 'Confirm', - style: TextStyle( - fontSize: 15.sp, - color: - SCGlobalConfig.businessLogicStrategy - .getRechargePageButtonTextColor(), - fontWeight: FontWeight.w700, - ), - ), - ), - ), - ], - ), - ), - ); - } - - void _confirmSelection() { - if (widget.packages.isEmpty || widget.channels.isEmpty) { - return; - } - final RechargePackageOption selected = widget.packages.firstWhere( - (RechargePackageOption item) => item.id == _selectedPackageId, - orElse: () => widget.packages.first, - ); - final RechargeChannelOption selectedChannel = widget.channels.firstWhere( - (RechargeChannelOption item) => item.code == _selectedChannelCode, - orElse: () => widget.channels.first, - ); - widget.onConfirm(selected, selectedChannel); - Navigator.of(context).pop(); - } - - Widget _buildPackageCard( - RechargePackageOption item, - int index, - bool isSelected, - ) { - return SCDebounceWidget( - onTap: () { - setState(() { - _selectedPackageId = item.id; - }); - }, - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(10.w), - border: Border.all( - color: - isSelected ? SocialChatTheme.primaryLight : Colors.transparent, - width: 1.4, - ), - ), - child: Column( - children: [ - SizedBox( - height: 24.w, - child: - item.badge.isEmpty - ? null - : Align( - alignment: Alignment.topRight, - child: Container( - margin: EdgeInsets.only(top: 8.w, right: 8.w), - padding: EdgeInsets.symmetric( - horizontal: 7.w, - vertical: 2.w, - ), - decoration: BoxDecoration( - color: SocialChatTheme.primaryLight.withValues( - alpha: 0.14, - ), - borderRadius: BorderRadius.circular(999.w), - ), - child: Text( - item.badge, - style: TextStyle( - fontSize: 9.sp, - color: const Color(0xff03523a), - fontWeight: FontWeight.w700, - ), - ), - ), - ), - ), - Image.asset( - SCGlobalConfig.businessLogicStrategy - .getRechargePageGoldIconByIndex(index), - width: 38.w, - height: 38.w, - ), - SizedBox(height: 6.w), - Padding( - padding: EdgeInsets.symmetric(horizontal: 6.w), - child: Text( - _formatWholeNumber(item.coins), - maxLines: 1, - overflow: TextOverflow.ellipsis, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 15.sp, - color: Colors.black.withValues(alpha: 0.82), - fontWeight: FontWeight.w700, - ), - ), - ), - SizedBox(height: 2.w), - Padding( - padding: EdgeInsets.symmetric(horizontal: 6.w), - child: Text( - item.bonusCoins > 0 - ? '+${_formatWholeNumber(item.bonusCoins)}' - : 'No bonus', - maxLines: 1, - overflow: TextOverflow.ellipsis, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 11.sp, - color: - item.bonusCoins > 0 - ? SocialChatTheme.primaryLight - : Colors.black.withValues(alpha: 0.45), - fontWeight: FontWeight.w600, - ), - ), - ), - const Spacer(), - Container( - width: double.infinity, - height: 26.w, - alignment: Alignment.center, - decoration: BoxDecoration( - color: const Color(0xffF5C550), - borderRadius: BorderRadius.only( - bottomLeft: Radius.circular(10.w), - bottomRight: Radius.circular(10.w), - ), - ), - child: Text( - item.priceLabel, - style: TextStyle( - fontSize: 11.sp, - color: const Color(0xff6F4B00), - fontWeight: FontWeight.w700, - ), - ), - ), - ], - ), - ), - ); - } - - Widget _buildChannelChip(RechargeChannelOption option) { - final bool isSelected = option.code == _selectedChannelCode; - return SCDebounceWidget( - onTap: () { - setState(() { - _selectedChannelCode = option.code; - }); - }, - child: AnimatedContainer( - duration: const Duration(milliseconds: 180), - padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 10.w), - decoration: BoxDecoration( - color: - isSelected - ? Colors.white.withValues(alpha: 0.16) - : Colors.white.withValues(alpha: 0.08), - borderRadius: BorderRadius.circular(8.w), - border: Border.all( - color: - isSelected - ? SocialChatTheme.primaryLight - : Colors.white.withValues(alpha: 0.14), - width: 1.1, - ), - ), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - option.name, - style: TextStyle( - fontSize: 13.sp, - color: Colors.white, - fontWeight: FontWeight.w700, - ), - ), - if (option.typeLabel.isNotEmpty) ...[ - SizedBox(height: 2.w), - Text( - option.typeLabel, - style: TextStyle( - fontSize: 10.sp, - color: Colors.white.withValues(alpha: 0.62), - fontWeight: FontWeight.w500, - ), - ), - ], - ], - ), - ), - ); - } - - Widget _buildEmptyHint(String message) { - return Container( - width: double.infinity, - padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 14.w), - decoration: BoxDecoration( - color: Colors.white.withValues(alpha: 0.08), - borderRadius: BorderRadius.circular(10.w), - ), - child: Text( - message, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 12.sp, - color: Colors.white.withValues(alpha: 0.68), - fontWeight: FontWeight.w500, - ), - ), - ); - } - - String _formatWholeNumber(int value) { - final String raw = value.toString(); - final StringBuffer buffer = StringBuffer(); - for (int i = 0; i < raw.length; i++) { - final int position = raw.length - i; - buffer.write(raw[i]); - if (position > 1 && position % 3 == 1) { - buffer.write(','); - } - } - return buffer.toString(); - } -} diff --git a/lib/modules/wallet/recharge/recharge_page.dart b/lib/modules/wallet/recharge/recharge_page.dart index f074764..eaa3c30 100644 --- a/lib/modules/wallet/recharge/recharge_page.dart +++ b/lib/modules/wallet/recharge/recharge_page.dart @@ -1,6 +1,5 @@ import 'dart:io'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:in_app_purchase/in_app_purchase.dart'; @@ -9,17 +8,12 @@ import 'package:yumi/app/constants/sc_global_config.dart'; import 'package:yumi/app/constants/sc_screen.dart'; import 'package:yumi/app/routes/sc_fluro_navigator.dart'; import 'package:yumi/app_localizations.dart'; -import 'package:yumi/modules/wallet/recharge/recharge_method_bottom_sheet.dart'; import 'package:yumi/modules/wallet/wallet_route.dart'; import 'package:yumi/services/auth/user_profile_manager.dart'; import 'package:yumi/services/payment/apple_payment_manager.dart'; import 'package:yumi/services/payment/google_payment_manager.dart'; -import 'package:yumi/services/payment/mifa_pay_manager.dart'; -import 'package:yumi/shared/business_logic/models/res/sc_mifa_pay_res.dart'; -import 'package:yumi/shared/tools/sc_lk_dialog_util.dart'; import 'package:yumi/ui_kit/components/appbar/socialchat_appbar.dart'; import 'package:yumi/ui_kit/components/sc_debounce_widget.dart'; -import 'package:yumi/ui_kit/components/sc_tts.dart'; import 'package:yumi/ui_kit/components/text/sc_text.dart'; class RechargePage extends StatefulWidget { @@ -34,16 +28,10 @@ class _RechargePageState extends State { static const Color _surfaceTextColor = Colors.white; static const Color _surfaceSubtleTextColor = Color(0xCCFFFFFF); - late final List _methodOptions; - - RechargeMethodType _selectedMethodType = RechargeMethodType.nativeStore; - @override void initState() { super.initState(); - _methodOptions = _buildMethodOptions(); Provider.of(context, listen: false).balance(); - Provider.of(context, listen: false).initialize(); if (Platform.isAndroid) { Provider.of( context, @@ -59,8 +47,6 @@ class _RechargePageState extends State { @override Widget build(BuildContext context) { - final MiFaPayManager miFaPayManager = context.watch(); - return Stack( children: [ Image.asset( @@ -102,18 +88,10 @@ class _RechargePageState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - _buildMethodSection(miFaPayManager), + _buildMethodSection(), SizedBox(height: 14.w), - Expanded( - child: - _selectedMethodType == - RechargeMethodType.nativeStore - ? _buildNativeProductList() - : _buildMiFaPayContent(miFaPayManager), - ), - if (_selectedMethodType == - RechargeMethodType.nativeStore && - Platform.isIOS) ...[ + Expanded(child: _buildNativeProductList()), + if (Platform.isIOS) ...[ SizedBox(height: 12.w), _buildFooterButton( title: @@ -130,19 +108,8 @@ class _RechargePageState extends State { ], SizedBox(height: 12.w), _buildFooterButton( - title: - _selectedMethodType == - RechargeMethodType.nativeStore - ? SCAppLocalizations.of(context)!.recharge - : _buildMiFaPayPrimaryTitle(miFaPayManager), - onTap: () { - if (_selectedMethodType == - RechargeMethodType.nativeStore) { - _processNativePurchase(); - return; - } - _handleMiFaPayPrimaryAction(miFaPayManager); - }, + title: SCAppLocalizations.of(context)!.recharge, + onTap: _processNativePurchase, ), SizedBox(height: 14.w), ], @@ -157,23 +124,6 @@ class _RechargePageState extends State { ); } - List _buildMethodOptions() { - return [ - RechargeMethodOption( - type: RechargeMethodType.nativeStore, - title: Platform.isAndroid ? 'Google Pay' : 'Apple Pay', - assetIconPath: - Platform.isAndroid ? 'sc_images/login/sc_icon_google.png' : null, - iconData: Platform.isIOS ? Icons.apple : null, - ), - const RechargeMethodOption( - type: RechargeMethodType.miFaPay, - title: 'MiFaPay', - assetIconPath: 'sc_images/index/sc_icon_recharge_agency.png', - ), - ]; - } - void _showRecordDialog() { showGeneralDialog( context: context, @@ -288,7 +238,7 @@ class _RechargePageState extends State { ); } - Widget _buildMethodSection(MiFaPayManager miFaPayManager) { + Widget _buildMethodSection() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -301,47 +251,13 @@ class _RechargePageState extends State { ), ), SizedBox(height: 10.w), - ..._methodOptions.map( - (RechargeMethodOption option) => - _buildMethodTile(option, miFaPayManager), - ), - ], - ); - } - - Widget _buildMethodTile( - RechargeMethodOption option, - MiFaPayManager miFaPayManager, - ) { - final bool isSelected = _selectedMethodType == option.type; - String trailingText = ''; - if (option.type == RechargeMethodType.miFaPay && - miFaPayManager.selectedCommodity != null) { - trailingText = _formatMiFaPriceLabel(miFaPayManager.selectedCommodity!); - } - - return Padding( - padding: EdgeInsets.only(bottom: 10.w), - child: SCDebounceWidget( - onTap: () { - setState(() { - _selectedMethodType = option.type; - }); - if (option.type == RechargeMethodType.miFaPay) { - _openMiFaPaySheet(miFaPayManager); - } - }, - child: AnimatedContainer( - duration: const Duration(milliseconds: 180), + Container( width: double.infinity, height: 58.w, padding: EdgeInsets.symmetric(horizontal: 14.w), decoration: BoxDecoration( - gradient: LinearGradient( - colors: - isSelected - ? const [Color(0x42FFFFFF), Color(0x24FFFFFF)] - : const [Color(0x33FFFFFF), Color(0x18FFFFFF)], + gradient: const LinearGradient( + colors: [Color(0x42FFFFFF), Color(0x24FFFFFF)], begin: AlignmentDirectional.centerStart, end: AlignmentDirectional.centerEnd, ), @@ -356,11 +272,11 @@ class _RechargePageState extends State { ), child: Row( children: [ - _buildMethodLeading(option), + _buildMethodLeading(), SizedBox(width: 14.w), Expanded( child: Text( - option.title, + Platform.isAndroid ? 'Google Pay' : 'Apple Pay', maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( @@ -370,49 +286,28 @@ class _RechargePageState extends State { ), ), ), - if (trailingText.isNotEmpty) - Padding( - padding: EdgeInsetsDirectional.only(end: 8.w), - child: Text( - trailingText, - style: TextStyle( - fontSize: 12.sp, - color: _surfaceSubtleTextColor.withValues(alpha: 0.82), - fontWeight: FontWeight.w600, - ), - ), - ), Icon( - isSelected - ? Icons.radio_button_checked - : Icons.radio_button_off_outlined, + Icons.radio_button_checked, size: 18.w, - color: - isSelected - ? _accentGoldColor - : _surfaceSubtleTextColor.withValues(alpha: 0.45), + color: _accentGoldColor, ), ], ), ), - ), + ], ); } - Widget _buildMethodLeading(RechargeMethodOption option) { - if (option.assetIconPath != null) { + Widget _buildMethodLeading() { + if (Platform.isAndroid) { return Image.asset( - option.assetIconPath!, + 'sc_images/login/sc_icon_google.png', width: 28.w, height: 28.w, fit: BoxFit.contain, ); } - return Icon( - option.iconData ?? CupertinoIcons.creditcard, - size: 24.w, - color: _surfaceTextColor, - ); + return Icon(Icons.apple, size: 24.w, color: _surfaceTextColor); } Widget _buildNativeProductList() { @@ -459,122 +354,6 @@ class _RechargePageState extends State { ); } - Widget _buildMiFaPayContent(MiFaPayManager miFaPayManager) { - if (miFaPayManager.isLoading && miFaPayManager.commodities.isEmpty) { - return Center(child: CupertinoActivityIndicator(radius: 14.w)); - } - - if (miFaPayManager.errorMessage.isNotEmpty && - miFaPayManager.commodities.isEmpty) { - return _buildMiFaPayStatusCard( - title: 'MiFaPay is temporarily unavailable', - detail: miFaPayManager.errorMessage, - actionText: 'Retry', - onTap: () { - miFaPayManager.reload(); - }, - ); - } - - if (miFaPayManager.commodities.isEmpty) { - return _buildMiFaPayStatusCard( - title: 'No MiFaPay products available', - detail: 'Please try again later.', - ); - } - - final SCMiFaPayCommodityItemRes? commodity = - miFaPayManager.selectedCommodity; - final SCMiFaPayChannelRes? channel = miFaPayManager.selectedChannel; - final SCMiFaPayCountryRes? country = miFaPayManager.selectedCountry; - - return _buildMiFaPayStatusCard( - title: - commodity == null - ? 'Tap MiFaPay to choose an amount' - : 'Selected ${_formatMiFaPriceLabel(commodity)}', - detail: - commodity == null - ? 'Choose amount and payment channel in the bottom sheet.' - : '${_formatWholeNumber(_parseWholeNumber(commodity.content))} +${_formatWholeNumber(_parseWholeNumber(commodity.awardContent))}', - actionText: - channel == null - ? null - : '${channel.channelName ?? ''}${country?.alphaTwo?.isNotEmpty == true ? ' ${country!.alphaTwo}' : ''}', - ); - } - - Widget _buildMiFaPayStatusCard({ - required String title, - required String detail, - String? actionText, - VoidCallback? onTap, - }) { - return Center( - child: Container( - width: double.infinity, - padding: EdgeInsets.symmetric(horizontal: 14.w, vertical: 16.w), - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [Color(0x33FFFFFF), Color(0x18FFFFFF)], - begin: AlignmentDirectional.topStart, - end: AlignmentDirectional.bottomEnd, - ), - borderRadius: BorderRadius.circular(10.w), - boxShadow: [ - BoxShadow( - color: Colors.black.withValues(alpha: 0.1), - blurRadius: 10.w, - offset: Offset(0, 3.w), - ), - ], - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - title, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14.sp, - color: _surfaceTextColor, - fontWeight: FontWeight.w700, - ), - ), - SizedBox(height: 8.w), - Text( - detail, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 12.sp, - color: _surfaceSubtleTextColor, - fontWeight: FontWeight.w500, - ), - ), - if ((actionText ?? '').isNotEmpty) ...[ - SizedBox(height: 10.w), - GestureDetector( - onTap: onTap, - child: Text( - actionText!, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 12.sp, - color: - onTap != null - ? _accentGoldColor - : _surfaceSubtleTextColor.withValues(alpha: 0.82), - fontWeight: FontWeight.w700, - ), - ), - ), - ], - ], - ), - ), - ); - } - Widget _buildRechargeEmptyState() { return Center( child: Column( @@ -641,167 +420,6 @@ class _RechargePageState extends State { } } - String _buildMiFaPayPrimaryTitle(MiFaPayManager miFaPayManager) { - if (miFaPayManager.isCreatingOrder) { - return 'Processing...'; - } - if (miFaPayManager.isLoading && miFaPayManager.commodities.isEmpty) { - return 'Loading...'; - } - if (miFaPayManager.errorMessage.isNotEmpty && - miFaPayManager.commodities.isEmpty) { - return 'Retry'; - } - return miFaPayManager.canCreateRecharge ? 'Pay now' : 'Choose amount'; - } - - void _handleMiFaPayPrimaryAction(MiFaPayManager miFaPayManager) { - if (miFaPayManager.isCreatingOrder) { - return; - } - if (miFaPayManager.errorMessage.isNotEmpty && - miFaPayManager.commodities.isEmpty) { - miFaPayManager.reload(); - return; - } - if (miFaPayManager.canCreateRecharge) { - miFaPayManager.createRecharge(context); - return; - } - _openMiFaPaySheet(miFaPayManager); - } - - void _openMiFaPaySheet(MiFaPayManager miFaPayManager) { - if (miFaPayManager.isLoading && miFaPayManager.commodities.isEmpty) { - SCTts.show('MiFaPay products are loading'); - return; - } - - final List packages = _buildMiFaPackages( - miFaPayManager.commodities, - ); - final List channels = _buildMiFaChannels( - miFaPayManager.channels, - ); - - if (packages.isEmpty || channels.isEmpty) { - if (miFaPayManager.errorMessage.isNotEmpty) { - SCTts.show(miFaPayManager.errorMessage); - } else { - SCTts.show('No MiFaPay product is available now'); - } - return; - } - - showBottomInBottomDialog( - context, - RechargeMethodBottomSheet( - method: _methodOptions.firstWhere( - (RechargeMethodOption item) => - item.type == RechargeMethodType.miFaPay, - ), - packages: packages, - channels: channels, - initialPackageId: miFaPayManager.selectedCommodity?.id, - initialChannelCode: miFaPayManager.selectedChannel?.channelCode, - onConfirm: ( - RechargePackageOption package, - RechargeChannelOption channel, - ) { - setState(() { - _selectedMethodType = RechargeMethodType.miFaPay; - }); - miFaPayManager.chooseCommodityById(package.id); - miFaPayManager.chooseChannelByCode(channel.code); - }, - ), - barrierColor: Colors.black.withValues(alpha: 0.35), - ); - } - - List _buildMiFaPackages( - List commodities, - ) { - return commodities - .where((SCMiFaPayCommodityItemRes item) => (item.id ?? '').isNotEmpty) - .map((SCMiFaPayCommodityItemRes item) { - final int coins = _parseWholeNumber(item.content); - final int bonusCoins = _parseWholeNumber(item.awardContent); - return RechargePackageOption( - id: item.id ?? '', - coins: coins, - bonusCoins: bonusCoins, - priceLabel: _formatMiFaPriceLabel(item), - badge: _buildMiFaBadge(coins, bonusCoins), - ); - }) - .toList(growable: false); - } - - List _buildMiFaChannels( - List channels, - ) { - return channels - .where( - (SCMiFaPayChannelRes item) => (item.channelCode ?? '').isNotEmpty, - ) - .map((SCMiFaPayChannelRes item) { - return RechargeChannelOption( - code: item.channelCode ?? '', - name: item.channelName ?? '', - typeLabel: _buildChannelTypeLabel(item), - ); - }) - .toList(growable: false); - } - - String _buildMiFaBadge(int coins, int bonusCoins) { - if (coins <= 0 || bonusCoins <= 0) { - return ''; - } - final double percent = bonusCoins * 100 / coins; - return '+${percent.toStringAsFixed(percent >= 10 ? 0 : 1)}%'; - } - - String _buildChannelTypeLabel(SCMiFaPayChannelRes channel) { - final List parts = []; - if ((channel.channelType ?? '').isNotEmpty) { - parts.add(channel.channelType!); - } - if ((channel.factoryChannel ?? '').isNotEmpty) { - parts.add(channel.factoryChannel!); - } - return parts.join(' '); - } - - String _formatMiFaPriceLabel(SCMiFaPayCommodityItemRes item) { - final String currency = item.currency ?? 'USD'; - final num amount = item.amount ?? item.amountUsd ?? 0; - final String formattedAmount = - amount % 1 == 0 ? amount.toInt().toString() : amount.toString(); - return '$currency $formattedAmount'; - } - - int _parseWholeNumber(String? value) { - if ((value ?? '').isEmpty) { - return 0; - } - return num.tryParse(value!)?.toInt() ?? 0; - } - - String _formatWholeNumber(num value) { - final String raw = value.toInt().toString(); - final StringBuffer buffer = StringBuffer(); - for (int i = 0; i < raw.length; i++) { - final int position = raw.length - i; - buffer.write(raw[i]); - if (position > 1 && position % 3 == 1) { - buffer.write(','); - } - } - return buffer.toString(); - } - Widget _buildGoogleProductItem( SelecteProductConfig productConfig, AndroidPaymentProcessor ref, diff --git a/lib/services/payment/mifa_pay_manager.dart b/lib/services/payment/mifa_pay_manager.dart deleted file mode 100644 index c2755bc..0000000 --- a/lib/services/payment/mifa_pay_manager.dart +++ /dev/null @@ -1,451 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; - -import 'package:dio/dio.dart'; -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; -import 'package:yumi/app_localizations.dart'; -import 'package:yumi/app/constants/sc_global_config.dart'; -import 'package:yumi/modules/wallet/recharge/mifa_pay_webview_page.dart'; -import 'package:yumi/services/auth/user_profile_manager.dart'; -import 'package:yumi/shared/business_logic/models/res/sc_mifa_pay_res.dart'; -import 'package:yumi/shared/data_sources/sources/local/user_manager.dart'; -import 'package:yumi/shared/data_sources/sources/repositories/sc_config_repository_imp.dart'; -import 'package:yumi/shared/data_sources/sources/repositories/sc_user_repository_impl.dart'; -import 'package:yumi/shared/tools/sc_loading_manager.dart'; -import 'package:yumi/ui_kit/components/sc_tts.dart'; - -class MiFaPayManager extends ChangeNotifier { - static const String defaultApplicationId = '2048200000000000701'; - static const String defaultPayCountryId = '2048200000000000401'; - static const String defaultPayCountryName = 'Saudi Arabia'; - static const String defaultPayCountryCode = 'SA'; - - bool _initialized = false; - bool _isLoading = false; - bool _isCreatingOrder = false; - String _errorMessage = ''; - String _applicationId = defaultApplicationId; - - List _countries = []; - SCMiFaPayCountryRes? _selectedCountry; - SCMiFaPayCommodityRes? _commodityRes; - SCMiFaPayCommodityItemRes? _selectedCommodity; - SCMiFaPayChannelRes? _selectedChannel; - - bool get initialized => _initialized; - - bool get isLoading => _isLoading; - - bool get isCreatingOrder => _isCreatingOrder; - - String get errorMessage => _errorMessage; - - String get applicationId => _applicationId; - - List get countries => _countries; - - SCMiFaPayCountryRes? get selectedCountry => _selectedCountry; - - SCMiFaPayCommodityRes? get commodityRes => _commodityRes; - - List get commodities => - _commodityRes?.commodity ?? []; - - List get channels => - _commodityRes?.channels ?? []; - - SCMiFaPayCommodityItemRes? get selectedCommodity => _selectedCommodity; - - SCMiFaPayChannelRes? get selectedChannel => _selectedChannel; - - bool get canCreateRecharge => - _selectedCountry != null && - _selectedCommodity != null && - _selectedChannel != null && - !_isLoading && - !_isCreatingOrder; - - Future initialize({bool force = false}) async { - if (_isLoading) { - return; - } - if (_initialized && !force) { - return; - } - - _isLoading = true; - _errorMessage = ''; - notifyListeners(); - - try { - await _loadCountries(); - await _loadCommodity(); - _initialized = true; - } catch (error) { - _errorMessage = _readErrorMessage(error); - debugPrint('MiFaPay initialize failed: $error'); - } finally { - _isLoading = false; - notifyListeners(); - } - } - - Future reload() async { - await initialize(force: true); - } - - void chooseCommodityById(String goodsId) { - if (goodsId.isEmpty) { - return; - } - for (final SCMiFaPayCommodityItemRes item in commodities) { - if (item.id == goodsId) { - _selectedCommodity = item; - notifyListeners(); - return; - } - } - } - - void chooseChannelByCode(String channelCode) { - if (channelCode.isEmpty) { - return; - } - for (final SCMiFaPayChannelRes item in channels) { - if (item.channelCode == channelCode) { - _selectedChannel = item; - notifyListeners(); - return; - } - } - } - - Future createRecharge(BuildContext context) async { - final SCMiFaPayCountryRes? country = _selectedCountry; - final SCMiFaPayCommodityItemRes? commodity = _selectedCommodity; - final SCMiFaPayChannelRes? channel = _selectedChannel; - final String userId = - AccountStorage().getCurrentUser()?.userProfile?.id ?? ""; - final NavigatorState navigator = Navigator.of(context); - final String purchaseSuccessMessage = - SCAppLocalizations.of(context)!.purchaseIsSuccessful; - const String paymentPendingMessage = 'Payment confirmation in progress'; - final Map payload = { - "applicationId": _applicationId, - "goodsId": commodity?.id ?? '', - "payCountryId": country?.id ?? '', - "userId": userId, - "channelCode": channel?.channelCode ?? '', - "newVersion": true, - }; - - if (country?.id?.isNotEmpty != true || - commodity?.id?.isNotEmpty != true || - channel?.channelCode?.isNotEmpty != true) { - SCTts.show('Please select MiFaPay amount and channel first'); - return; - } - if (userId.isEmpty) { - SCTts.show('User id is empty'); - return; - } - if (_isCreatingOrder) { - return; - } - - final SocialChatUserProfileManager profileManager = - Provider.of(context, listen: false); - final double balanceBeforeRecharge = profileManager.myBalance; - - try { - _isCreatingOrder = true; - notifyListeners(); - SCLoadingManager.show(context: context); - _logRequest( - method: 'POST', - path: '/order/web/pay/recharge', - body: payload, - ); - final SCMiFaPayRechargeRes res = await SCConfigRepositoryImp() - .mifaPayRecharge( - applicationId: _applicationId, - goodsId: commodity!.id!, - payCountryId: country!.id!, - userId: userId, - channelCode: channel!.channelCode!, - ); - SCLoadingManager.hide(); - _logResponse(tag: 'recharge', data: res.toJson()); - - if ((res.requestUrl ?? "").isEmpty) { - SCTts.show('MiFaPay requestUrl is empty'); - return; - } - - await navigator.push( - MaterialPageRoute( - builder: - (_) => MiFaPayWebViewPage( - title: 'MiFaPay', - requestUrl: res.requestUrl!, - ), - ), - ); - - final bool rechargeSucceeded = await _waitForRechargeResult( - profileManager, - balanceBeforeRecharge, - ); - SCTts.show( - rechargeSucceeded ? purchaseSuccessMessage : paymentPendingMessage, - ); - } catch (error) { - _logError( - tag: 'recharge', - path: '/order/web/pay/recharge', - error: error, - body: payload, - ); - final String message = _readErrorMessage(error); - SCTts.show(message); - debugPrint('MiFaPay createRecharge failed: $error'); - } finally { - SCLoadingManager.hide(); - _isCreatingOrder = false; - notifyListeners(); - } - } - - Future _loadCountries() async { - List countries = []; - try { - _logRequest(method: 'GET', path: '/order/web/pay/country'); - countries = await SCConfigRepositoryImp().mifaPayCountries(); - _logResponse( - tag: 'country', - data: - countries.map((SCMiFaPayCountryRes item) => item.toJson()).toList(), - ); - } catch (error) { - _logError(tag: 'country', path: '/order/web/pay/country', error: error); - debugPrint('MiFaPay countries fallback: $error'); - } - - if (countries.isEmpty) { - countries = [_fallbackCountry()]; - } - - _countries = countries; - final String currentCountryId = _selectedCountry?.id ?? ''; - _selectedCountry = countries.firstWhere( - (SCMiFaPayCountryRes item) => item.id == currentCountryId, - orElse: () => countries.first, - ); - } - - Future _loadCommodity() async { - final String payCountryId = - _selectedCountry?.id?.isNotEmpty == true - ? _selectedCountry!.id! - : defaultPayCountryId; - final Map queryParams = { - "applicationId": _applicationId, - "payCountryId": payCountryId, - "type": "GOLD", - }; - - try { - _logRequest( - method: 'GET', - path: '/order/web/pay/commodity', - queryParams: queryParams, - ); - final SCMiFaPayCommodityRes res = await SCConfigRepositoryImp() - .mifaPayCommodity( - applicationId: _applicationId, - payCountryId: payCountryId, - ); - _logResponse(tag: 'commodity', data: res.toJson()); - - _commodityRes = res; - _applicationId = res.application?.id ?? _applicationId; - - final List commodityList = commodities; - final String currentGoodsId = _selectedCommodity?.id ?? ''; - _selectedCommodity = - commodityList.isEmpty - ? null - : commodityList.firstWhere( - (SCMiFaPayCommodityItemRes item) => item.id == currentGoodsId, - orElse: () => commodityList.first, - ); - - final List channelList = channels; - final String currentChannelCode = _selectedChannel?.channelCode ?? ''; - _selectedChannel = - channelList.isEmpty - ? null - : channelList.firstWhere( - (SCMiFaPayChannelRes item) => - item.channelCode == currentChannelCode, - orElse: () => channelList.first, - ); - } catch (error) { - _logError( - tag: 'commodity', - path: '/order/web/pay/commodity', - error: error, - queryParams: queryParams, - ); - rethrow; - } - } - - Future _refreshWalletState( - SocialChatUserProfileManager profileManager, - ) async { - try { - final double balance = await SCAccountRepository().balance(); - profileManager.updateBalance(balance); - } catch (error) { - debugPrint('MiFaPay balance refresh failed: $error'); - } - - try { - await profileManager.fetchUserProfileData(loadGuardCount: false); - } catch (error) { - debugPrint('MiFaPay profile refresh failed: $error'); - } - } - - Future _pollWalletState( - SocialChatUserProfileManager profileManager, - ) async { - for (int index = 0; index < 2; index++) { - await Future.delayed(const Duration(seconds: 3)); - await _refreshWalletState(profileManager); - } - } - - Future _waitForRechargeResult( - SocialChatUserProfileManager profileManager, - double previousBalance, - ) async { - await _refreshWalletState(profileManager); - if (profileManager.myBalance > previousBalance) { - return true; - } - - for (int index = 0; index < 5; index++) { - await Future.delayed(const Duration(seconds: 2)); - await _refreshWalletState(profileManager); - if (profileManager.myBalance > previousBalance) { - return true; - } - } - - unawaited(_pollWalletState(profileManager)); - return false; - } - - SCMiFaPayCountryRes _fallbackCountry() { - return SCMiFaPayCountryRes( - id: defaultPayCountryId, - countryName: defaultPayCountryName, - alphaTwo: defaultPayCountryCode, - nationalFlag: '', - ); - } - - String _readErrorMessage(Object error) { - final String raw = error.toString(); - return raw - .replaceFirst('Exception: ', '') - .replaceFirst('DioException [unknown]: ', '') - .trim(); - } - - void _logRequest({ - required String method, - required String path, - Map? queryParams, - Map? body, - }) { - debugPrint('[MiFaPay][Request] $method ${_buildUrl(path)}'); - if (queryParams != null && queryParams.isNotEmpty) { - debugPrint('[MiFaPay][Query] ${_safeJson(queryParams)}'); - } - if (body != null && body.isNotEmpty) { - debugPrint('[MiFaPay][Body] ${_safeJson(body)}'); - } - } - - void _logResponse({required String tag, required dynamic data}) { - debugPrint('[MiFaPay][Response][$tag] ${_safeJson(data)}'); - } - - void _logError({ - required String tag, - required String path, - required Object error, - Map? queryParams, - Map? body, - }) { - debugPrint('[MiFaPay][Error][$tag] ${_buildUrl(path)}'); - if (queryParams != null && queryParams.isNotEmpty) { - debugPrint('[MiFaPay][ErrorQuery][$tag] ${_safeJson(queryParams)}'); - } - if (body != null && body.isNotEmpty) { - debugPrint('[MiFaPay][ErrorBody][$tag] ${_safeJson(body)}'); - } - - if (error is DioException) { - debugPrint('[MiFaPay][Dio][$tag] type=${error.type}'); - debugPrint( - '[MiFaPay][Dio][$tag] status=${error.response?.statusCode} message=${error.message}', - ); - if (error.requestOptions.path.isNotEmpty) { - debugPrint( - '[MiFaPay][Dio][$tag] requestPath=${error.requestOptions.path}', - ); - } - if (error.requestOptions.queryParameters.isNotEmpty) { - debugPrint( - '[MiFaPay][Dio][$tag] requestQuery=${_safeJson(error.requestOptions.queryParameters)}', - ); - } - if (error.requestOptions.data != null) { - debugPrint( - '[MiFaPay][Dio][$tag] requestData=${_safeJson(error.requestOptions.data)}', - ); - } - if (error.response?.data != null) { - debugPrint( - '[MiFaPay][Dio][$tag] responseData=${_safeJson(error.response?.data)}', - ); - } - } else { - debugPrint('[MiFaPay][Error][$tag] $error'); - } - } - - String _buildUrl(String path) { - final String host = SCGlobalConfig.apiHost; - if (host.endsWith('/') && path.startsWith('/')) { - return '${host.substring(0, host.length - 1)}$path'; - } - if (!host.endsWith('/') && !path.startsWith('/')) { - return '$host/$path'; - } - return '$host$path'; - } - - String _safeJson(dynamic data) { - try { - return jsonEncode(data); - } catch (_) { - return data.toString(); - } - } -} diff --git a/lib/shared/business_logic/models/res/sc_mifa_pay_res.dart b/lib/shared/business_logic/models/res/sc_mifa_pay_res.dart index c4db1f6..3e9d56c 100644 --- a/lib/shared/business_logic/models/res/sc_mifa_pay_res.dart +++ b/lib/shared/business_logic/models/res/sc_mifa_pay_res.dart @@ -298,6 +298,42 @@ class SCMiFaPayRechargeRes { } } +class SCMiFaPayOrderStatusRes { + SCMiFaPayOrderStatusRes({bool? paid, String? statusText, dynamic rawBody}) { + _paid = paid; + _statusText = statusText; + _rawBody = rawBody; + } + + SCMiFaPayOrderStatusRes.fromJson(dynamic json) { + _rawBody = json; + _paid = _resolvePaid(json); + _statusText = _resolveStatusText(json); + } + + bool? _paid; + String? _statusText; + dynamic _rawBody; + + bool get isPaid => _paid == true; + + String? get statusText => _statusText; + + dynamic get rawBody => _rawBody; + + Map toJson() { + final dynamic body = _rawBody; + if (body is Map) { + return body; + } + return { + 'paid': _paid, + 'statusText': _statusText, + 'rawBody': body, + }; + } +} + String? _stringValue(dynamic value) { if (value == null) { return null; @@ -315,3 +351,102 @@ num? _numValue(dynamic value) { } return num.tryParse(value.toString()); } + +bool? _boolValue(dynamic value) { + if (value == null) { + return null; + } + if (value is bool) { + return value; + } + if (value is num) { + return value != 0; + } + final String normalized = value.toString().trim().toLowerCase(); + if ([ + 'true', + 'success', + 'succeeded', + 'paid', + 'done', + 'completed', + ].contains(normalized)) { + return true; + } + if ([ + 'false', + 'pending', + 'processing', + 'failed', + 'cancelled', + ].contains(normalized)) { + return false; + } + return null; +} + +bool? _resolvePaid(dynamic json) { + final bool? direct = _boolValue(json); + if (direct != null) { + return direct; + } + + if (json is Map) { + const List boolKeys = [ + 'paid', + 'success', + 'paySuccess', + 'orderPaid', + 'finished', + 'completed', + 'result', + ]; + for (final String key in boolKeys) { + final bool? value = _boolValue(json[key]); + if (value != null) { + return value; + } + } + + const List statusKeys = [ + 'status', + 'orderStatus', + 'payStatus', + 'tradeStatus', + ]; + for (final String key in statusKeys) { + final bool? value = _boolValue(json[key]); + if (value != null) { + return value; + } + } + } + + return null; +} + +String? _resolveStatusText(dynamic json) { + if (json == null) { + return null; + } + if (json is String) { + return json; + } + if (json is Map) { + const List keys = [ + 'status', + 'orderStatus', + 'payStatus', + 'tradeStatus', + 'message', + 'msg', + ]; + for (final String key in keys) { + final String? value = _stringValue(json[key]); + if (value != null) { + return value; + } + } + } + return _stringValue(json); +} diff --git a/lib/shared/business_logic/models/res/sc_sign_in_reward_res.dart b/lib/shared/business_logic/models/res/sc_sign_in_reward_res.dart new file mode 100644 index 0000000..e58218d --- /dev/null +++ b/lib/shared/business_logic/models/res/sc_sign_in_reward_res.dart @@ -0,0 +1,211 @@ +Map _asMap(dynamic json) { + if (json is Map) { + return json; + } + return {}; +} + +List _asList(dynamic json) { + if (json is List) { + return json; + } + return const []; +} + +String _asString(dynamic value) { + if (value == null) { + return ''; + } + return value.toString(); +} + +int _asInt(dynamic value) { + if (value is int) { + return value; + } + if (value is num) { + return value.toInt(); + } + return int.tryParse(_asString(value)) ?? 0; +} + +bool _asBool(dynamic value) { + if (value is bool) { + return value; + } + if (value is num) { + return value != 0; + } + final normalized = _asString(value).trim().toLowerCase(); + return normalized == 'true' || normalized == '1'; +} + +class SCSignInRewardItem { + const SCSignInRewardItem({ + required this.id, + required this.type, + required this.name, + required this.content, + required this.quantity, + required this.cover, + required this.remark, + }); + + final String id; + final String type; + final String name; + final String content; + final int quantity; + final String cover; + final String remark; + + factory SCSignInRewardItem.fromJson(dynamic json) { + final map = _asMap(json); + return SCSignInRewardItem( + id: _asString(map['id']), + type: _asString(map['type']), + name: _asString(map['name']), + content: _asString(map['content']), + quantity: _asInt(map['quantity']), + cover: _asString(map['cover']), + remark: _asString(map['remark']), + ); + } +} + +class SCSignInRewardDay { + const SCSignInRewardDay({ + required this.dayIndex, + required this.rewardGroupId, + required this.rewardGroupName, + required this.rewardItems, + required this.signed, + required this.todayTarget, + }); + + final int dayIndex; + final String rewardGroupId; + final String rewardGroupName; + final List rewardItems; + final bool signed; + final bool todayTarget; + + factory SCSignInRewardDay.fromJson(dynamic json) { + final map = _asMap(json); + return SCSignInRewardDay( + dayIndex: _asInt(map['dayIndex']), + rewardGroupId: _asString(map['rewardGroupId']), + rewardGroupName: _asString(map['rewardGroupName']), + rewardItems: + _asList( + map['rewardItems'], + ).map((item) => SCSignInRewardItem.fromJson(item)).toList(), + signed: _asBool(map['signed']), + todayTarget: _asBool(map['todayTarget']), + ); + } +} + +class SCSignInRewardStatusRes { + const SCSignInRewardStatusRes({ + required this.userId, + required this.sysOrigin, + required this.configured, + required this.enabled, + required this.available, + required this.timezone, + required this.cycleDays, + required this.currentDate, + required this.signedToday, + required this.currentStreak, + required this.nextDayIndex, + required this.days, + }); + + final String userId; + final String sysOrigin; + final bool configured; + final bool enabled; + final bool available; + final String timezone; + final int cycleDays; + final String currentDate; + final bool signedToday; + final int currentStreak; + final int nextDayIndex; + final List days; + + bool get canShowDialog => + configured && enabled && available && !signedToday && days.isNotEmpty; + + factory SCSignInRewardStatusRes.fromJson(dynamic json) { + final map = _asMap(json); + return SCSignInRewardStatusRes( + userId: _asString(map['userId']), + sysOrigin: _asString(map['sysOrigin']), + configured: _asBool(map['configured']), + enabled: _asBool(map['enabled']), + available: _asBool(map['available']), + timezone: _asString(map['timezone']), + cycleDays: _asInt(map['cycleDays']), + currentDate: _asString(map['currentDate']), + signedToday: _asBool(map['signedToday']), + currentStreak: _asInt(map['currentStreak']), + nextDayIndex: _asInt(map['nextDayIndex']), + days: + _asList( + map['days'], + ).map((day) => SCSignInRewardDay.fromJson(day)).toList(), + ); + } +} + +class SCSignInRewardCheckInRes { + const SCSignInRewardCheckInRes({ + required this.success, + required this.alreadySigned, + required this.userId, + required this.sysOrigin, + required this.claimDate, + required this.dayIndex, + required this.streakCount, + required this.rewardGroupId, + required this.rewardGroupName, + required this.rewardItems, + required this.status, + }); + + final bool success; + final bool alreadySigned; + final String userId; + final String sysOrigin; + final String claimDate; + final int dayIndex; + final int streakCount; + final String rewardGroupId; + final String rewardGroupName; + final List rewardItems; + final String status; + + bool get isClaimed => success || alreadySigned; + + factory SCSignInRewardCheckInRes.fromJson(dynamic json) { + final map = _asMap(json); + return SCSignInRewardCheckInRes( + success: _asBool(map['success']), + alreadySigned: _asBool(map['alreadySigned']), + userId: _asString(map['userId']), + sysOrigin: _asString(map['sysOrigin']), + claimDate: _asString(map['claimDate']), + dayIndex: _asInt(map['dayIndex']), + streakCount: _asInt(map['streakCount']), + rewardGroupId: _asString(map['rewardGroupId']), + rewardGroupName: _asString(map['rewardGroupName']), + rewardItems: + _asList( + map['rewardItems'], + ).map((item) => SCSignInRewardItem.fromJson(item)).toList(), + status: _asString(map['status']), + ); + } +} diff --git a/lib/shared/business_logic/repositories/config_repository.dart b/lib/shared/business_logic/repositories/config_repository.dart index e5aa227..7eb2372 100644 --- a/lib/shared/business_logic/repositories/config_repository.dart +++ b/lib/shared/business_logic/repositories/config_repository.dart @@ -77,6 +77,9 @@ abstract class SocialChatConfigRepository { required String channelCode, }); + ///MiFaPay 订单状态 + Future mifaPayOrderStatus({required String orderId}); + ///等级资源 Future configLevel(); diff --git a/lib/shared/business_logic/repositories/user_repository.dart b/lib/shared/business_logic/repositories/user_repository.dart index 4bcbbdd..136e00e 100644 --- a/lib/shared/business_logic/repositories/user_repository.dart +++ b/lib/shared/business_logic/repositories/user_repository.dart @@ -1,9 +1,12 @@ -import 'package:yumi/shared/business_logic/models/res/join_room_res.dart' hide WearBadge; +import 'package:yumi/shared/business_logic/models/res/join_room_res.dart' + hide WearBadge; import 'package:yumi/shared/business_logic/models/req/sc_mobile_auth_cmd.dart'; import 'package:yumi/shared/business_logic/models/res/sc_edit_room_info_res.dart'; -import 'package:yumi/shared/business_logic/models/res/follow_room_res.dart' hide WearBadge; -import 'package:yumi/shared/business_logic/models/res/follow_user_res.dart' hide WearBadge; +import 'package:yumi/shared/business_logic/models/res/follow_room_res.dart' + hide WearBadge; +import 'package:yumi/shared/business_logic/models/res/follow_user_res.dart' + hide WearBadge; import 'package:yumi/shared/business_logic/models/res/sc_gold_record_res.dart'; import 'package:yumi/shared/business_logic/models/res/login_res.dart'; import 'package:yumi/shared/business_logic/models/res/message_friend_user_res.dart'; @@ -12,9 +15,11 @@ import 'package:yumi/shared/business_logic/models/res/sc_prop_coupon_list_res.da import 'package:yumi/shared/business_logic/models/res/sc_prop_coupon_record_list_res.dart'; import 'package:yumi/shared/business_logic/models/res/sc_public_message_page_res.dart'; import 'package:yumi/shared/business_logic/models/res/room_black_list_res.dart'; -import 'package:yumi/shared/business_logic/models/res/room_res.dart' hide WearBadge; +import 'package:yumi/shared/business_logic/models/res/room_res.dart' + hide WearBadge; import 'package:yumi/shared/business_logic/models/req/sc_user_profile_cmd.dart'; import 'package:yumi/shared/business_logic/models/res/sc_rtc_token_res.dart'; +import 'package:yumi/shared/business_logic/models/res/sc_sign_in_reward_res.dart'; import 'package:yumi/shared/business_logic/models/res/sc_sign_in_res.dart'; import 'package:yumi/shared/business_logic/models/res/sc_task_list_res.dart'; import 'package:yumi/shared/business_logic/models/res/sc_user_counter_res.dart'; @@ -63,15 +68,15 @@ abstract class SocialChatUserRepository { ///发送心跳 Future heartbeat(String status, bool upMick, {String? roomId}); - ///上麦心跳 - Future anchorHeartbeat(String roomId); - - ///声网token - Future getRtcToken( - String channel, - String userId, { - bool isPublisher = false, - }); + ///上麦心跳 + Future anchorHeartbeat(String roomId); + + ///声网token + Future getRtcToken( + String channel, + String userId, { + bool isPublisher = false, + }); ///退出房间 Future quitRoom(String roomId); @@ -146,7 +151,6 @@ abstract class SocialChatUserRepository { ///获取用户关系计数 SUBSCRIPTION:订阅、FANS:粉丝、FRIEND:朋友,访客. Future> userCounter(String userId); - ///用户等级 Future userLevelConsumptionExp(String userId, String type); @@ -159,6 +163,12 @@ abstract class SocialChatUserRepository { ///签到领奖 Future checkInReceive(String id, String resourceGroupId); + ///签到奖励状态 + Future signInRewardStatus(); + + ///执行签到 + Future signInRewardCheckIn(); + ///添加代理 Future teamCreate(String ownUserId); @@ -226,7 +236,6 @@ abstract class SocialChatUserRepository { ///赠送道具券 Future couponSend(String couponNo, String receiverId); - ///处理用户违规 Future userViolationHandle( String userId, @@ -236,7 +245,6 @@ abstract class SocialChatUserRepository { List? imageUrls, }); - ///验证是否是好友 Future friendRelationCheck(String userId); @@ -269,5 +277,4 @@ abstract class SocialChatUserRepository { ///注销账号 Future logoutAccount(); - } diff --git a/lib/shared/data_sources/sources/repositories/sc_config_repository_imp.dart b/lib/shared/data_sources/sources/repositories/sc_config_repository_imp.dart index a09de20..9c0ecf2 100644 --- a/lib/shared/data_sources/sources/repositories/sc_config_repository_imp.dart +++ b/lib/shared/data_sources/sources/repositories/sc_config_repository_imp.dart @@ -242,6 +242,19 @@ class SCConfigRepositoryImp implements SocialChatConfigRepository { return result; } + ///order/web/pay/order-status + @override + Future mifaPayOrderStatus({ + required String orderId, + }) async { + final result = await http.get( + "/order/web/pay/order-status", + queryParams: {"orderId": orderId}, + fromJson: (json) => SCMiFaPayOrderStatusRes.fromJson(json), + ); + return result; + } + ///sys/static-config/level @override Future configLevel() async { diff --git a/lib/shared/data_sources/sources/repositories/sc_user_repository_impl.dart b/lib/shared/data_sources/sources/repositories/sc_user_repository_impl.dart index 1bbd5f5..5b26365 100644 --- a/lib/shared/data_sources/sources/repositories/sc_user_repository_impl.dart +++ b/lib/shared/data_sources/sources/repositories/sc_user_repository_impl.dart @@ -1,214 +1,218 @@ -import 'package:flutter/foundation.dart'; -import 'package:yumi/shared/business_logic/models/req/sc_user_profile_cmd.dart'; -import 'package:yumi/shared/business_logic/models/res/sc_gold_record_res.dart'; -import 'package:yumi/shared/business_logic/models/res/sc_prop_coupon_list_res.dart'; -import 'package:yumi/shared/business_logic/models/res/sc_prop_coupon_record_list_res.dart'; -import 'package:yumi/shared/business_logic/models/res/sc_public_message_page_res.dart'; -import 'package:yumi/shared/business_logic/models/res/room_res.dart' - hide WearBadge; -import 'package:yumi/shared/business_logic/models/res/sc_rtc_token_res.dart'; -import 'package:yumi/shared/business_logic/models/res/sc_task_list_res.dart'; -import 'package:yumi/shared/business_logic/models/res/sc_user_counter_res.dart'; -import 'package:yumi/shared/business_logic/models/res/sc_user_identity_res.dart'; -import 'package:yumi/shared/business_logic/models/res/sc_user_level_exp_res.dart'; -import 'package:yumi/shared/business_logic/models/res/sc_user_red_packet_grab_res.dart'; -import 'package:yumi/shared/business_logic/models/res/sc_user_red_packet_send_res.dart'; -import 'package:yumi/shared/business_logic/models/req/sc_mobile_auth_cmd.dart'; -import 'package:yumi/shared/business_logic/models/res/sc_edit_room_info_res.dart'; -import 'package:yumi/shared/business_logic/models/res/follow_room_res.dart' - hide WearBadge; -import 'package:yumi/shared/business_logic/models/res/follow_user_res.dart' - hide WearBadge; -import 'package:yumi/shared/business_logic/models/res/join_room_res.dart' - hide WearBadge; -import 'package:yumi/shared/business_logic/models/res/login_res.dart'; -import 'package:yumi/shared/business_logic/models/res/message_friend_user_res.dart'; -import 'package:yumi/shared/business_logic/models/res/my_room_res.dart'; -import 'package:yumi/shared/business_logic/models/res/room_black_list_res.dart'; -import 'package:yumi/shared/business_logic/models/res/sc_sign_in_res.dart'; -import 'package:yumi/shared/business_logic/models/res/sc_violation_handle_res.dart'; -import 'package:yumi/shared/business_logic/repositories/user_repository.dart'; -import 'package:yumi/shared/data_sources/sources/remote/net/network_client.dart'; -import 'package:yumi/shared/tools/sc_room_profile_cache.dart'; - -class SCAccountRepository implements SocialChatUserRepository { - static SCAccountRepository? _instance; - - SCAccountRepository._internal(); - - factory SCAccountRepository() { - return _instance ??= SCAccountRepository._internal(); - } - - @override - Future getUser(String id) async { - final result = await http.get( - "", - fromJson: (json) => SocialChatLoginRes.fromJson(json), - ); - return result; - } - - ///auth/account/create - @override - Future regist( - String type, - String openId, - SCUserProfileCmd userProfileCmd, { - SCMobileAuthCmd? mobileAuthCmd, - String invitePeople = "", - }) async { - var param = {}; - param["type"] = type; - param["openId"] = openId; - param["profile"] = userProfileCmd.toJson(); - if (mobileAuthCmd != null) { - param["mobile"] = mobileAuthCmd.toJson(); - } - if (invitePeople.isNotEmpty) { - param["invitePeople"] = invitePeople; - } - final result = await http.post( - "aa35848b37e5ba74d93e5a1f719c579cb289b5940c15040473b6f57550de35df", - data: param, - fromJson: (json) => SocialChatLoginRes.fromJson(json), - ); - return result; - } - - ///auth/account/login - @override - Future loginForAccount(String account, String pwd) async { - final result = await http.post( - "e64f27b9ba6b37881120f4584a5444a5c684d8491b703d0af953e5cc6a5f4cec", - data: {"account": account, "pwd": pwd}, - fromJson: (json) => SocialChatLoginRes.fromJson(json), - ); - return result; - } - - ///auth/account/login/channel - @override - Future loginForChannel( - String authType, - String openId, - ) async { - final result = await http.post( - "e64f27b9ba6b37881120f4584a5444a5531a33eb137749a5decad584f58aaa44", - data: {"authType": authType, "openId": openId}, - fromJson: (json) => SocialChatLoginRes.fromJson(json), - ); - return result; - } - - ///room/relation/follow - @override - Future> followRoomList({String? lastId}) async { - Map param = {}; - if (lastId != null) { - param["lastId"] = lastId; - } - final result = await http.get( - "59a548c91daed73d9becdf4eba7daf628ba84731fa88da5433b944ca2e6d6098", - queryParams: param, - fromJson: - (json) => - (json as List).map((e) => FollowRoomRes.fromJson(e)).toList(), - ); - return result.map(SCRoomProfileCache.applyToFollowRoomRes).toList(); - } - - ///room/relation/joined - @override - Future> joined() async { - final result = await http.get( - "06ff6a670e789a391a7af40ce5d6b15c326060e4bcd797edd258ca1d8bb139be", - fromJson: - (json) => - (json as List).map((e) => FollowRoomRes.fromJson(e)).toList(), - ); - return result.map(SCRoomProfileCache.applyToFollowRoomRes).toList(); - } - - ///room/relation/trace - @override - Future> trace({String? lastId}) async { - Map param = {}; - if (lastId != null) { - param["lastId"] = lastId; - } - final result = await http.get( - "95523e566901192267301b47f35adc8d5de33f03aaf96911b1a0c8131b938f28", - queryParams: param, - fromJson: - (json) => - (json as List).map((e) => FollowRoomRes.fromJson(e)).toList(), - ); - return result.map(SCRoomProfileCache.applyToFollowRoomRes).toList(); - } - - ///room/profile - @override - Future myProfile() async { - final result = await http.get( - "1e41384e55cbd6c2374608b129e2ed27", - fromJson: (json) => MyRoomRes.fromJson(json), - ); - return SCRoomProfileCache.applyToMyRoomRes(result); - } - - ///room/live-voice/create - @override - Future createRoom() async { - final result = await http.post( - "363603111e51beac2d183014dd29b81cf01ca103e12cc332b59b5a8e39c778ec", - fromJson: (json) => SocialChatRoomRes.fromJson(json), - ); - return result; - } - - ///room/live-voice/entry - @override - Future entryRoom( - String roomId, { - String? pwd, - String redPackId = "", - bool needOpenRedenvelope = false, - }) async { - var param = {}; - param["roomId"] = roomId; - if (pwd != null) { - param["pwd"] = pwd; - } - //自定义字段,用来在输入密码框api拦截时获取 - param["needOpenRedenvelope"] = needOpenRedenvelope; - param["redPackId"] = redPackId; - final result = await http.post( - "363603111e51beac2d183014dd29b81c219577507bcc9c6abfaf327548fed0e0", - data: param, - fromJson: (json) => JoinRoomRes.fromJson(json), - ); - return SCRoomProfileCache.applyToJoinRoomRes(result); - } - - ///live/user/heartbeat - @override - Future heartbeat(String status, bool upMick, {String? roomId}) async { - var parm = {}; - parm["status"] = status; - parm["upMick"] = upMick; - parm["task"] = true; - if (roomId != null) { - parm["sessionId"] = roomId; - } - final result = await http.post( - "58f9485b5b9f401c6a14bc1e6534122c7a085bb5f6a613094188ca56fe8bc03d", - data: parm, - fromJson: (json) => {}, - ); - return result; - } - +import 'dart:convert'; + +import 'package:dio/dio.dart'; +import 'package:flutter/foundation.dart'; +import 'package:yumi/shared/business_logic/models/req/sc_user_profile_cmd.dart'; +import 'package:yumi/shared/business_logic/models/res/sc_gold_record_res.dart'; +import 'package:yumi/shared/business_logic/models/res/sc_prop_coupon_list_res.dart'; +import 'package:yumi/shared/business_logic/models/res/sc_prop_coupon_record_list_res.dart'; +import 'package:yumi/shared/business_logic/models/res/sc_public_message_page_res.dart'; +import 'package:yumi/shared/business_logic/models/res/room_res.dart' + hide WearBadge; +import 'package:yumi/shared/business_logic/models/res/sc_rtc_token_res.dart'; +import 'package:yumi/shared/business_logic/models/res/sc_task_list_res.dart'; +import 'package:yumi/shared/business_logic/models/res/sc_user_counter_res.dart'; +import 'package:yumi/shared/business_logic/models/res/sc_user_identity_res.dart'; +import 'package:yumi/shared/business_logic/models/res/sc_user_level_exp_res.dart'; +import 'package:yumi/shared/business_logic/models/res/sc_user_red_packet_grab_res.dart'; +import 'package:yumi/shared/business_logic/models/res/sc_user_red_packet_send_res.dart'; +import 'package:yumi/shared/business_logic/models/req/sc_mobile_auth_cmd.dart'; +import 'package:yumi/shared/business_logic/models/res/sc_edit_room_info_res.dart'; +import 'package:yumi/shared/business_logic/models/res/follow_room_res.dart' + hide WearBadge; +import 'package:yumi/shared/business_logic/models/res/follow_user_res.dart' + hide WearBadge; +import 'package:yumi/shared/business_logic/models/res/join_room_res.dart' + hide WearBadge; +import 'package:yumi/shared/business_logic/models/res/login_res.dart'; +import 'package:yumi/shared/business_logic/models/res/message_friend_user_res.dart'; +import 'package:yumi/shared/business_logic/models/res/my_room_res.dart'; +import 'package:yumi/shared/business_logic/models/res/room_black_list_res.dart'; +import 'package:yumi/shared/business_logic/models/res/sc_sign_in_reward_res.dart'; +import 'package:yumi/shared/business_logic/models/res/sc_sign_in_res.dart'; +import 'package:yumi/shared/business_logic/models/res/sc_violation_handle_res.dart'; +import 'package:yumi/shared/business_logic/repositories/user_repository.dart'; +import 'package:yumi/shared/data_sources/sources/remote/net/network_client.dart'; +import 'package:yumi/shared/tools/sc_room_profile_cache.dart'; + +class SCAccountRepository implements SocialChatUserRepository { + static SCAccountRepository? _instance; + + SCAccountRepository._internal(); + + factory SCAccountRepository() { + return _instance ??= SCAccountRepository._internal(); + } + + @override + Future getUser(String id) async { + final result = await http.get( + "", + fromJson: (json) => SocialChatLoginRes.fromJson(json), + ); + return result; + } + + ///auth/account/create + @override + Future regist( + String type, + String openId, + SCUserProfileCmd userProfileCmd, { + SCMobileAuthCmd? mobileAuthCmd, + String invitePeople = "", + }) async { + var param = {}; + param["type"] = type; + param["openId"] = openId; + param["profile"] = userProfileCmd.toJson(); + if (mobileAuthCmd != null) { + param["mobile"] = mobileAuthCmd.toJson(); + } + if (invitePeople.isNotEmpty) { + param["invitePeople"] = invitePeople; + } + final result = await http.post( + "aa35848b37e5ba74d93e5a1f719c579cb289b5940c15040473b6f57550de35df", + data: param, + fromJson: (json) => SocialChatLoginRes.fromJson(json), + ); + return result; + } + + ///auth/account/login + @override + Future loginForAccount(String account, String pwd) async { + final result = await http.post( + "e64f27b9ba6b37881120f4584a5444a5c684d8491b703d0af953e5cc6a5f4cec", + data: {"account": account, "pwd": pwd}, + fromJson: (json) => SocialChatLoginRes.fromJson(json), + ); + return result; + } + + ///auth/account/login/channel + @override + Future loginForChannel( + String authType, + String openId, + ) async { + final result = await http.post( + "e64f27b9ba6b37881120f4584a5444a5531a33eb137749a5decad584f58aaa44", + data: {"authType": authType, "openId": openId}, + fromJson: (json) => SocialChatLoginRes.fromJson(json), + ); + return result; + } + + ///room/relation/follow + @override + Future> followRoomList({String? lastId}) async { + Map param = {}; + if (lastId != null) { + param["lastId"] = lastId; + } + final result = await http.get( + "59a548c91daed73d9becdf4eba7daf628ba84731fa88da5433b944ca2e6d6098", + queryParams: param, + fromJson: + (json) => + (json as List).map((e) => FollowRoomRes.fromJson(e)).toList(), + ); + return result.map(SCRoomProfileCache.applyToFollowRoomRes).toList(); + } + + ///room/relation/joined + @override + Future> joined() async { + final result = await http.get( + "06ff6a670e789a391a7af40ce5d6b15c326060e4bcd797edd258ca1d8bb139be", + fromJson: + (json) => + (json as List).map((e) => FollowRoomRes.fromJson(e)).toList(), + ); + return result.map(SCRoomProfileCache.applyToFollowRoomRes).toList(); + } + + ///room/relation/trace + @override + Future> trace({String? lastId}) async { + Map param = {}; + if (lastId != null) { + param["lastId"] = lastId; + } + final result = await http.get( + "95523e566901192267301b47f35adc8d5de33f03aaf96911b1a0c8131b938f28", + queryParams: param, + fromJson: + (json) => + (json as List).map((e) => FollowRoomRes.fromJson(e)).toList(), + ); + return result.map(SCRoomProfileCache.applyToFollowRoomRes).toList(); + } + + ///room/profile + @override + Future myProfile() async { + final result = await http.get( + "1e41384e55cbd6c2374608b129e2ed27", + fromJson: (json) => MyRoomRes.fromJson(json), + ); + return SCRoomProfileCache.applyToMyRoomRes(result); + } + + ///room/live-voice/create + @override + Future createRoom() async { + final result = await http.post( + "363603111e51beac2d183014dd29b81cf01ca103e12cc332b59b5a8e39c778ec", + fromJson: (json) => SocialChatRoomRes.fromJson(json), + ); + return result; + } + + ///room/live-voice/entry + @override + Future entryRoom( + String roomId, { + String? pwd, + String redPackId = "", + bool needOpenRedenvelope = false, + }) async { + var param = {}; + param["roomId"] = roomId; + if (pwd != null) { + param["pwd"] = pwd; + } + //自定义字段,用来在输入密码框api拦截时获取 + param["needOpenRedenvelope"] = needOpenRedenvelope; + param["redPackId"] = redPackId; + final result = await http.post( + "363603111e51beac2d183014dd29b81c219577507bcc9c6abfaf327548fed0e0", + data: param, + fromJson: (json) => JoinRoomRes.fromJson(json), + ); + return SCRoomProfileCache.applyToJoinRoomRes(result); + } + + ///live/user/heartbeat + @override + Future heartbeat(String status, bool upMick, {String? roomId}) async { + var parm = {}; + parm["status"] = status; + parm["upMick"] = upMick; + parm["task"] = true; + if (roomId != null) { + parm["sessionId"] = roomId; + } + final result = await http.post( + "58f9485b5b9f401c6a14bc1e6534122c7a085bb5f6a613094188ca56fe8bc03d", + data: parm, + fromJson: (json) => {}, + ); + return result; + } + ///external/im-trtc/tmp/agora/sig @override Future getRtcToken( @@ -227,918 +231,1066 @@ class SCAccountRepository implements SocialChatUserRepository { ); return result; } - - ///live/room/quit - @override - Future quitRoom(String roomId) async { - final result = await http.get( - "3e451c31ab651a577a3b7796b32041e7", - queryParams: {"roomId": roomId}, - fromJson: (json) => json as bool, - ); - return result; - } - - ///room/profile - @override - Future editRoomInfo( - String roomId, - String roomCover, - String roomName, - String roomDesc, - String event, - ) async { - final payload = { - "id": roomId, - "roomId": roomId, - "roomCover": roomCover, - "cover": roomCover, - "roomName": roomName, - "roomDesc": roomDesc, - "event": event, - }; - debugPrint("[Room Cover Save] request payload=$payload"); - final result = await http.put( - "1e41384e55cbd6c2374608b129e2ed27", - data: payload, - fromJson: (json) => SCEditRoomInfoRes.fromJson(json), - ); - debugPrint("[Room Cover Save] response=${result.toJson()}"); - await SCRoomProfileCache.saveRoomProfile( - roomId: roomId, - roomCover: roomCover, - roomName: roomName, - roomDesc: roomDesc, - ); - return result; - } - - ///user/user-profile - @override - Future loadUserInfo(String userId) async { - final result = await http.get( - "2fa1d4f56bb726558904ce2a50b83f961e1cf9b945681bdfb3d4cf7a5ecfc943", - queryParams: {"userId": userId}, - fromJson: (json) => SocialChatUserProfile.fromJson(json), - ); - return result; - } - - ///room/relation/follow/action - @override - Future followRoom(String roomId) async { - final result = await http.post( - "59a548c91daed73d9becdf4eba7daf6226c857599fe196e293c826f60146fa9f", - data: {"roomId": roomId}, - fromJson: (json) => json as bool, - ); - return result; - } - - ///user/support-relation/follow - @override - Future followUser(String userId) async { - final result = await http.post( - "5ee2ca437d883bcd9a4030c44b20b059555c9f831613c06da141d92ffef9d8b7", - data: {"userId": userId}, - fromJson: (json) => json as bool, - ); - return result; - } - - ///team/heartbeat - @override - Future anchorHeartbeat(String roomId) async { - final result = await http.get( - "d28c7d4eeb945fb765c8206c8f79d77f", - queryParams: {"roomId": roomId}, - fromJson: (json) => {}, - ); - return result; - } - - ///wallet/gold/balance - @override - Future balance() async { - final result = await http.get( - "6e864e3aa03c0c398fa2d8f909d21aef2f0b7f5a6a5c523c28407ff12d872b31", - fromJson: (json) => json as double, - ); - return result; - } - - ///user/user-profile/search - @override - Future searchUser(String account) async { - final result = await http.get( - "2fa1d4f56bb726558904ce2a50b83f9604b0c834cdef3e5a6c3f81b198ab9a4b", - queryParams: {"account": account}, - fromJson: (json) => SocialChatUserProfile.fromJson(json), - ); - return result; - } - - ///user/account/account-pwd-reset - @override - Future pwdReset(String pwd) async { - final result = await http.post( - "745ce65f1d68f106702ad3c636aca0e0ac57f82127b3ac414551924946593db7", - data: {"pwd": pwd}, - fromJson: (json) => null, - ); - return result; - } - - ///user/user-auth-type/account-is-bind - @override - Future accountIsBind() async { - final result = await http.get( - "0bc43bb5ac93dd30919c4a7c3bbd60335894d3a279a24600c6a7e5dc9536f0e10e634626c0d4977d4df50adfb36c576e", - fromJson: (json) => json as bool, - ); - return result; - } - - ///user/user-auth-type/account-bind - @override - Future bind(String pwd) async { - final result = await http.post( - "0bc43bb5ac93dd30919c4a7c3bbd6033963c952c9eca882afb1a172894887db3574aff257ce7e668d08f4caccd1c6232", - data: {"pwd": pwd}, - fromJson: (json) => json as bool, - ); - return result; - } - - ///user/user-auth-type/account-update - @override - Future updatePwd(String pwd, String oldPwd) async { - final result = await http.post( - "0bc43bb5ac93dd30919c4a7c3bbd60336a92ac11dbc1fb082f877af0c807bf9f6ad9a4bc80736146ebc083f857e42b4f", - data: {"pwd": pwd, "oldPwd": oldPwd}, - fromJson: (json) => json as bool, - ); - return result; - } - - ///room/blacklist - @override - Future> roomBlacklist( - String roomId, - String lastId, - ) async { - Map parm = {}; - parm["roomId"] = roomId; - if (lastId != "0") { - parm["lastId"] = lastId; - } - final result = await http.get>( - "9ce0dac3a29735467208f19ed4edc330", - queryParams: parm, - fromJson: - (json) => - (json as List).map((e) => RoomBlackListRes.fromJson(e)).toList(), - ); - return result; - } - - ///user/user-profile/update - @override - Future updateUserInfo({ - String? userAvatar, - String? userNickname, - num? userSex, - num? age, - num? bornYear, - num? bornMonth, - num? bornDay, - String? countryId, - String? hobby, - String? autograph, - List? backgroundPhotos, - List? personalPhotos, - }) async { - Map parm = {}; - if (userAvatar != null) { - parm["userAvatar"] = userAvatar; - } - if (userNickname != null) { - parm["userNickname"] = userNickname; - } - if (userSex != null) { - parm["userSex"] = userSex; - } - - if (age != null) { - parm["age"] = age; - } - - if (bornYear != null) { - parm["bornYear"] = bornYear; - } - - if (bornMonth != null) { - parm["bornMonth"] = bornMonth; - } - if (bornDay != null) { - parm["bornDay"] = bornDay; - } - if (countryId != null) { - parm["countryId"] = countryId; - } - if (hobby != null) { - parm["hobby"] = hobby; - } - if (autograph != null) { - parm["autograph"] = autograph; - } - if (backgroundPhotos != null) { - parm["backgroundPhotos"] = backgroundPhotos; - } - if (personalPhotos != null) { - parm["personalPhotos"] = personalPhotos; - } - - final result = await http.put( - "2fa1d4f56bb726558904ce2a50b83f96365e62b6aa808acde7b56d2d5945fbe4", - data: parm, - fromJson: (json) => SocialChatUserProfile.fromJson(json), - ); - return result; - } - - ///user/support-relation/follow/my-list - @override - Future> followMyList({ - String? account, - String? lastId, - }) async { - Map parm = {}; - if (account != null) { - parm["account"] = account; - } - if (lastId != null) { - parm["lastId"] = lastId; - } - final result = await http.get>( - "5ee2ca437d883bcd9a4030c44b20b059984d86f34396dfa8045aa8afe71cb567bc4a9e8c4704c0f73c085e7ab50e7fdb", - queryParams: parm, - fromJson: - (json) => - (json as List).map((e) => FollowUserRes.fromJson(e)).toList(), - ); - return result; - } - - ///user/support-relation/fans/my-list - @override - Future> fansMyList({ - String? account, - String? lastId, - }) async { - Map parm = {}; - if (account != null) { - parm["account"] = account; - } - if (lastId != null) { - parm["lastId"] = lastId; - } - final result = await http.get>( - "5ee2ca437d883bcd9a4030c44b20b05995242771a17d74da900d0d3c02debf52397bb180e31856d94bf25d85eb342787", - queryParams: parm, - fromJson: - (json) => - (json as List).map((e) => FollowUserRes.fromJson(e)).toList(), - ); - return result; - } - - ///wallet/gold/this-month/asset-record - @override - Future> goldRecord({num? type, String? lastId}) async { - Map parm = {}; - if (type != null) { - parm["type"] = type; - } - if (lastId != null) { - parm["lastId"] = lastId; - } - final result = await http.get>( - "aabf121bb4c193ccceac70586aa16f3b06ad35ecd192416cde0bc922045e1dda68a9458578aa4b21fc86df1010fa2ca2", - queryParams: parm, - fromJson: - (json) => - (json as List).map((e) => SCGoldRecordRes.fromJson(e)).toList(), - ); - return result; - } - - ///user/support-relation/counter - @override - Future> userCounter(String userId) async { - Map parm = {}; - parm["userId"] = userId; - final result = await http.get>( - "5ee2ca437d883bcd9a4030c44b20b05980e9d6b90837a95599c7f32e68756428", - queryParams: parm, - fromJson: - (json) => - (json as List).map((e) => SCUserCounterRes.fromJson(e)).toList(), - ); - return result; - } - - ///app/h5/identity - @override - Future userIdentity({String? userId}) async { - Map parm = {}; - if (userId != null) { - parm["userId"] = userId; - } - final result = await http.get( - "d29121f09fa26c45b5322df6de0fc25b", - queryParams: parm, - fromJson: (json) => SCUserIdentityRes.fromJson(json), - ); - return result; - } - - ///user/user-level/consumption/exp - @override - Future userLevelConsumptionExp( - String userId, - String type, - ) async { - Map parm = {}; - parm["userId"] = userId; - parm["type"] = type; - final result = await http.get( - "9863061ae38e7d452fdd7f95840a952f2751db44c8c4787063c9ccf1dcd80366", - queryParams: parm, - fromJson: (json) => SCUserLevelExpRes.fromJson(json), - ); - return result; - } - - ///task/check/in/today - @override - Future checkInToday() async { - final result = await http.get( - "b5908b3dc914a82da088fadf8be59213143ec06ec0fc08a0d7d915f0556e3821", - fromJson: (json) => json as bool, - ); - return result; - } - - ///task/check/in/list/award - @override - Future sginListAward() async { - final result = await http.get( - "acdc80e923fd539da1401826ee3e99169b3b4b9cccf8933804239f0e070c54c7", - fromJson: (json) => SCSignInRes.fromJson(json), - ); - return result; - } - - ///task/check/in/receive - @override - Future checkInReceive(String id, String resourceGroupId) async { - Map parm = {}; - parm["id"] = id; - parm["resourceGroupId"] = resourceGroupId; - final result = await http.post( - "cd4f02cf4ef018533e882d3cbb23a6aeaeb1d976c8b96774303e69619d73e630", - data: parm, - fromJson: (json) => json as int, - ); - return result; - } - - ///team/create - @override - Future teamCreate(String ownUserId) async { - Map parm = {}; - parm["ownUserId"] = ownUserId; - final result = await http.post( - "9d3a59e43ee9cf3729f57abc0c596005", - data: parm, - fromJson: (json) => json as bool, - ); - return result; - } - - ///public-message/page - @override - Future publicMessagePage( - String type, - num pageNo, - num pageSize, - ) async { - Map parm = {}; - parm["type"] = type; - parm["pageNo"] = pageNo; - parm["pageSize"] = pageSize; - final result = await http.get( - "38801b8e4843cf3f040b20e8e7a32554118a90740b43e354a7fdc9ac837e0671", - queryParams: parm, - fromJson: (json) => SCPublicMessagePageRes.fromJson(json), - ); - return result; - } - - ///user/friend-relation/list - @override - Future> friendList({String? lastId}) async { - Map parm = {}; - if (lastId != null) { - parm["lastId"] = lastId; - } - final result = await http.get>( - "4aff0909d268eb1d0a7f1ded14d28357d8c0811eb69bd36aaaf7bf3d8bf0e486", - queryParams: parm, - fromJson: - (json) => - (json as List) - .map((e) => MessageFriendUserRes.fromJson(e)) - .toList(), - ); - return result; - } - - ///user/friend-relation/search - @override - Future> friendSearch(String account) async { - Map parm = {}; - parm["account"] = account; - final result = await http.get>( - "4aff0909d268eb1d0a7f1ded14d28357879fc2cee9e8f2051bbaccb8bf07e372", - queryParams: parm, - fromJson: - (json) => - (json as List) - .map((e) => MessageFriendUserRes.fromJson(e)) - .toList(), - ); - return result; - } - - ///team/invite-message-process - @override - Future inviteHost(String id, String status) async { - Map parm = {}; - parm["id"] = id; - parm["status"] = status; - final result = await http.post( - "e5989162aa832581f74b9a383248e4b8317f6af14ecd57b0c1e01a5e47e7414d", - data: parm, - fromJson: (json) => json as bool, - ); - return result; - } - - ///team/bd/invite-message-process - @override - Future inviteAgent(String id, String status) async { - Map parm = {}; - parm["id"] = id; - parm["status"] = status; - final result = await http.post( - "5e44a26c2a5805a21846bf04cb67a75108fa66d1b5877cd04fb8d1761aa95547", - data: parm, - fromJson: (json) => json as bool, - ); - return result; - } - - ///team/bd/invite-bd-message-process - @override - Future inviteBD(String id, String status) async { - Map parm = {}; - parm["id"] = id; - parm["status"] = status; - final result = await http.post( - "bbdc8997a823680923efb54a9d31072eabf7f2c09434925bdc6cd2a847f93dcfba2fafbaede21817c8d7e89774331852", - data: parm, - fromJson: (json) => json as bool, - ); - return result; - } - - ///team/bd/invite-bdleader-message-process - @override - Future inviteBDLeader(String id, String status) async { - Map parm = {}; - parm["id"] = id; - parm["status"] = status; - final result = await http.post( - "bbdc8997a823680923efb54a9d31072eb14922cefad1be12ebcebd874a66585c7f7f07aa8fdbecc97b3d68d3389dd470", - data: parm, - fromJson: (json) => json as bool, - ); - return result; - } - - ///team/bd/invite-recharge-agent-message-process - @override - Future inviteRechargeAgent(String id, String status) async { - Map parm = {}; - parm["id"] = id; - parm["status"] = status; - final result = await http.post( - "771f90aeda269f6e1eb1421f4335c8bf02f5ada0ff7a70fca49e8b367fd079ffd991f48d7a7af790a9593ff2caf1f6fc", - data: parm, - fromJson: (json) => json as bool, - ); - return result; - } - - ///user/support-relation/follow/check - @override - Future followCheck(String userId) async { - Map parm = {}; - parm["userId"] = userId; - final result = await http.get( - "5ee2ca437d883bcd9a4030c44b20b059cda65c203d085b6a0dc3eb6c86372454b6de76cbe76f15fa0a33e1759219198c", - queryParams: parm, - fromJson: (json) => json as bool, - ); - return result; - } - - ///user/support-relation/follow-new - @override - Future followNew(String userId) async { - Map parm = {}; - parm["userId"] = userId; - final result = await http.post( - "5ee2ca437d883bcd9a4030c44b20b059787556c9e7c91af11f63f466fc47a7a6574aff257ce7e668d08f4caccd1c6232", - data: parm, - fromJson: (json) => json as bool, - ); - return result; - } - - ///app/v2/task/list - @override - Future> tasks() async { - final result = await http.get>( - "6e87048da643aa0388a9e46ea391daff574aff257ce7e668d08f4caccd1c6232", - fromJson: - (json) => - (json as List).map((e) => SCTaskListRes.fromJson(e)).toList(), - ); - return result; - } - - ///app/v2/task/reward - @override - Future taskReward(num taskId) async { - Map parm = {}; - parm["taskId"] = taskId; - final result = await http.get( - "0047abf8502867ed03180e3a6b505d411832ea9bebe4ec426a7036c865082475", - queryParams: parm, - fromJson: (json) => json as bool, - ); - return result; - } - - ///user/support-relation/visitor/list - @override - Future> visitorList(num pageNumber) async { - Map parm = {}; - parm["pageNumber"] = pageNumber; - final result = await http.get>( - "5ee2ca437d883bcd9a4030c44b20b05903ab400c9bf27c42312a7e75b67b25a0397bb180e31856d94bf25d85eb342787", - queryParams: parm, - fromJson: - (json) => - (json as List).map((e) => FollowUserRes.fromJson(e)).toList(), - ); - return result; - } - - ///prop/coupon/list - @override - Future propCouponList( - num size, - num current, { - int? couponType, - }) async { - Map parm = {}; - parm["size"] = size; - parm["current"] = current; - if (couponType != null) { - parm["couponType"] = couponType; - } - final result = await http.post( - "c05bb66ab1d14464aa75f1842e222ce0574aff257ce7e668d08f4caccd1c6232", - data: parm, - fromJson: (json) => SCPropCouponListRes.fromJson(json), - ); - return result; - } - - ///prop/coupon/record/list - @override - Future couponRecordList( - num size, - num current, { - int? couponType, - int? status, - }) async { - Map parm = {}; - parm["size"] = size; - parm["current"] = current; - if (couponType != null) { - parm["couponType"] = couponType; - } - if (status != null) { - parm["status"] = status; - } - final result = await http.post( - "0348972fba6d4c510c1860e435c3f68297e6790742d0344ce6b20c597ee86fd1", - data: parm, - fromJson: (json) => SCPropCouponRecordListRes.fromJson(json), - ); - return result; - } - - ///prop/coupon/use - @override - Future couponUse(String couponNo) async { - Map parm = {}; - parm["couponNo"] = couponNo; - final result = await http.post( - "6163f60d541d3361be0d3f8ef816fc1d", - data: parm, - fromJson: (json) => json as bool, - ); - return result; - } - - ///prop/coupon/create - @override - Future couponSend(String couponNo, String receiverId) async { - Map parm = {}; - parm["couponNo"] = couponNo; - parm["receiverId"] = receiverId; - final result = await http.post( - "431750258fbc9a54a3298bf431007fd56ad9a4bc80736146ebc083f857e42b4f", - data: parm, - fromJson: (json) => json as bool, - ); - return result; - } - - ///user/badge/own/list - @override - Future> badgeOwnList(String type) async { - Map parm = {}; - parm["type"] = type; - final result = await http.get>( - "2d234c6012ceaca8dbd3923bb17b2adaf13e23fb57376accca26ee78f1baa860", - queryParams: parm, - fromJson: - (json) => (json as List).map((e) => WearBadge.fromJson(e)).toList(), - ); - return result; - } - - ///user/badge/toggle - @override - Future badgeToggle(String badgeId) async { - Map parm = {}; - parm["badgeId"] = badgeId; - final result = await http.post( - "84169ec3c928dde3a22cb4b7b6ae95c31e1cf9b945681bdfb3d4cf7a5ecfc943", - data: parm, - fromJson: (json) => json as bool, - ); - return result; - } - - ///user-violation/handle - @override - Future userViolationHandle( - String userId, - int violationType, - int operationType, - String description, { - List? imageUrls, - }) async { - Map parm = {}; - parm["userId"] = userId; - parm["violationType"] = violationType; - parm["operationType"] = operationType; - parm["description"] = description; - if (imageUrls != null && imageUrls.isNotEmpty) { - parm["screenshotUrls"] = imageUrls; - } - final result = await http.post( - "cc84151e5fba2824710e0645046729a06f894acdcdbac7ccb7e88e9d69ee3eff", - data: parm, - fromJson: (json) => SCViolationHandleRes.fromJson(json), - ); - return result; - } - - ///user/cp-relationship/create-apply - @override - Future cpRelationshipSendApply(String acceptApplyUserId) async { - Map parm = {}; - parm["acceptApplyUserId"] = acceptApplyUserId; - final result = await http.post( - "b06a43ca828553e84580a84da4a3af6135e967dbd0d9edde6478905c4b167fd37b53dae821c941c8c13570fbc26665ba", - data: parm, - fromJson: (json) => json as bool, - ); - return result; - } - - ///user/cp-relationship/process-apply - @override - Future cpRelationshipProcessApply(String applyId, bool agree) async { - Map parm = {}; - parm["applyId"] = applyId; - parm["agree"] = agree; - final result = await http.post( - "b06a43ca828553e84580a84da4a3af61cb64264b44425ec78a0115bfc976a827fd57dd4d0233d969f8991e901a14e144", - data: parm, - fromJson: (json) => json as bool, - ); - return result; - } - - ///user/cp-relationship/dismiss-apply - @override - Future cpRelationshipDismissApply(String cpUserId) async { - Map parm = {}; - parm["cpUserId"] = cpUserId; - final result = await http.get( - "b06a43ca828553e84580a84da4a3af6147b0e44e9311c7615dee77b6c4c425a1fd57dd4d0233d969f8991e901a14e144", - queryParams: parm, - fromJson: (json) => json as bool, - ); - return result; - } - - ///user/friend-relation/check - @override - Future friendRelationCheck(String userId) async { - Map parm = {}; - parm["userId"] = userId; - final result = await http.get( - "4aff0909d268eb1d0a7f1ded14d28357691f1c364e338d7fc3c50cf21be0f908", - queryParams: parm, - fromJson: (json) => json as bool, - ); - return result; - } - - ///user/red-packet/create - @override - Future userRedPacketSend( - String receiverUserId, - String totalAmount, - ) async { - Map parm = {}; - parm["receiverUserId"] = receiverUserId; - parm["totalAmount"] = totalAmount; - final result = await http.post( - "69585024cc7ee090d1e29ff7ca160a45f01ca103e12cc332b59b5a8e39c778ec", - data: parm, - fromJson: (json) => SCUserRedPacketSendRes.fromJson(json), - ); - return result; - } - - ///user/red-packet/detail - @override - Future userRedPacketDetail(String packetId) async { - Map parm = {}; - parm["packetId"] = packetId; - final result = await http.get( - "69585024cc7ee090d1e29ff7ca160a457f342deecb1b83d2d8429c59146f10f0", - queryParams: parm, - fromJson: (json) => SCUserRedPacketSendRes.fromJson(json), - ); - return result; - } - - ///user/red-packet/grab - @override - Future userRedPacketGrab(String packetId) async { - Map parm = {}; - parm["packetId"] = packetId; - final result = await http.post( - "69585024cc7ee090d1e29ff7ca160a450b2a61d0ce4f3f4d50875dcc95b640af", - data: parm, - fromJson: (json) => SCUserRedPacketGrabRes.fromJson(json), - ); - return result; - } - - ///user/blacklist/list - @override - Future> userBlacklistList({ - String? account, - String? lastId, - }) async { - Map parm = {}; - if (account != null) { - parm["account"] = account; - } - if (lastId != null) { - parm["lastId"] = lastId; - } - final result = await http.get>( - "62bd6154ca9eb9207f3e50294ed18035f13e23fb57376accca26ee78f1baa860", - queryParams: parm, - fromJson: - (json) => - (json as List) - .map((e) => MessageFriendUserRes.fromJson(e)) - .toList(), - ); - return result; - } - - ///user/blacklist/check - @override - Future blacklistCheck(String shieldUserId) async { - Map parm = {}; - parm["shieldUserId"] = shieldUserId; - final result = await http.post( - "66644b702102d48f4284444b05b1200deda65d2aec525e95d29625cf93fa9e45", - data: parm, - fromJson: (json) => json as bool, - ); - return result; - } - - ///user/blacklist - @override - Future addUserBlacklist(String shieldUserId) async { - Map parm = {}; - parm["shieldUserId"] = shieldUserId; - final result = await http.post( - "3f6e2326c10aaed6e637ac0d78a20a3b", - data: parm, - fromJson: (json) => json as bool, - ); - return result; - } - - ///user/blacklist/cancel - @override - Future deleteUserBlacklist(String shieldUserId) async { - Map parm = {}; - parm["shieldUserId"] = shieldUserId; - final result = await http.post( - "66644b702102d48f4284444b05b1200d13afc33ba8e2ca51c7245d9201b4569d", - data: parm, - fromJson: (json) => json as bool, - ); - return result; - } - - ///auth/logout - @override - Future logoutAccount() async { - final result = await http.delete( - "814a34263274ff501f4ca9ae76c4aae3", - fromJson: (json) => json as bool, - ); - return result; - } - - ///user/vip/ability/update - @override - Future userVipAbilityUpdate({ - String? contactMode, - bool? kickPrevention, - bool? mysteriousInvisibility, - bool? antiBlock, - }) async { - Map parm = {}; - if (contactMode != null) { - parm["contactMode"] = contactMode; - } - if (kickPrevention != null) { - parm["kickPrevention"] = kickPrevention; - } - if (mysteriousInvisibility != null) { - parm["mysteriousInvisibility"] = mysteriousInvisibility; - } - if (antiBlock != null) { - parm["antiBlock"] = antiBlock; - } - final result = await http.post( - "9bad890ecd3a153658cbe38367fcc46f3db9e152c7701ff2e5e1d4261f763895", - data: parm, - fromJson: (json) => json as bool, - ); - return result; - } -} + + ///live/room/quit + @override + Future quitRoom(String roomId) async { + final result = await http.get( + "3e451c31ab651a577a3b7796b32041e7", + queryParams: {"roomId": roomId}, + fromJson: (json) => json as bool, + ); + return result; + } + + ///room/profile + @override + Future editRoomInfo( + String roomId, + String roomCover, + String roomName, + String roomDesc, + String event, + ) async { + final payload = { + "id": roomId, + "roomId": roomId, + "roomCover": roomCover, + "cover": roomCover, + "roomName": roomName, + "roomDesc": roomDesc, + "event": event, + }; + debugPrint("[Room Cover Save] request payload=$payload"); + final result = await http.put( + "1e41384e55cbd6c2374608b129e2ed27", + data: payload, + fromJson: (json) => SCEditRoomInfoRes.fromJson(json), + ); + debugPrint("[Room Cover Save] response=${result.toJson()}"); + await SCRoomProfileCache.saveRoomProfile( + roomId: roomId, + roomCover: roomCover, + roomName: roomName, + roomDesc: roomDesc, + ); + return result; + } + + ///user/user-profile + @override + Future loadUserInfo(String userId) async { + final result = await http.get( + "2fa1d4f56bb726558904ce2a50b83f961e1cf9b945681bdfb3d4cf7a5ecfc943", + queryParams: {"userId": userId}, + fromJson: (json) => SocialChatUserProfile.fromJson(json), + ); + return result; + } + + ///room/relation/follow/action + @override + Future followRoom(String roomId) async { + final result = await http.post( + "59a548c91daed73d9becdf4eba7daf6226c857599fe196e293c826f60146fa9f", + data: {"roomId": roomId}, + fromJson: (json) => json as bool, + ); + return result; + } + + ///user/support-relation/follow + @override + Future followUser(String userId) async { + final result = await http.post( + "5ee2ca437d883bcd9a4030c44b20b059555c9f831613c06da141d92ffef9d8b7", + data: {"userId": userId}, + fromJson: (json) => json as bool, + ); + return result; + } + + ///team/heartbeat + @override + Future anchorHeartbeat(String roomId) async { + final result = await http.get( + "d28c7d4eeb945fb765c8206c8f79d77f", + queryParams: {"roomId": roomId}, + fromJson: (json) => {}, + ); + return result; + } + + ///wallet/gold/balance + @override + Future balance() async { + final result = await http.get( + "6e864e3aa03c0c398fa2d8f909d21aef2f0b7f5a6a5c523c28407ff12d872b31", + fromJson: (json) => json as double, + ); + return result; + } + + ///user/user-profile/search + @override + Future searchUser(String account) async { + final result = await http.get( + "2fa1d4f56bb726558904ce2a50b83f9604b0c834cdef3e5a6c3f81b198ab9a4b", + queryParams: {"account": account}, + fromJson: (json) => SocialChatUserProfile.fromJson(json), + ); + return result; + } + + ///user/account/account-pwd-reset + @override + Future pwdReset(String pwd) async { + final result = await http.post( + "745ce65f1d68f106702ad3c636aca0e0ac57f82127b3ac414551924946593db7", + data: {"pwd": pwd}, + fromJson: (json) => null, + ); + return result; + } + + ///user/user-auth-type/account-is-bind + @override + Future accountIsBind() async { + final result = await http.get( + "0bc43bb5ac93dd30919c4a7c3bbd60335894d3a279a24600c6a7e5dc9536f0e10e634626c0d4977d4df50adfb36c576e", + fromJson: (json) => json as bool, + ); + return result; + } + + ///user/user-auth-type/account-bind + @override + Future bind(String pwd) async { + final result = await http.post( + "0bc43bb5ac93dd30919c4a7c3bbd6033963c952c9eca882afb1a172894887db3574aff257ce7e668d08f4caccd1c6232", + data: {"pwd": pwd}, + fromJson: (json) => json as bool, + ); + return result; + } + + ///user/user-auth-type/account-update + @override + Future updatePwd(String pwd, String oldPwd) async { + final result = await http.post( + "0bc43bb5ac93dd30919c4a7c3bbd60336a92ac11dbc1fb082f877af0c807bf9f6ad9a4bc80736146ebc083f857e42b4f", + data: {"pwd": pwd, "oldPwd": oldPwd}, + fromJson: (json) => json as bool, + ); + return result; + } + + ///room/blacklist + @override + Future> roomBlacklist( + String roomId, + String lastId, + ) async { + Map parm = {}; + parm["roomId"] = roomId; + if (lastId != "0") { + parm["lastId"] = lastId; + } + final result = await http.get>( + "9ce0dac3a29735467208f19ed4edc330", + queryParams: parm, + fromJson: + (json) => + (json as List).map((e) => RoomBlackListRes.fromJson(e)).toList(), + ); + return result; + } + + ///user/user-profile/update + @override + Future updateUserInfo({ + String? userAvatar, + String? userNickname, + num? userSex, + num? age, + num? bornYear, + num? bornMonth, + num? bornDay, + String? countryId, + String? hobby, + String? autograph, + List? backgroundPhotos, + List? personalPhotos, + }) async { + Map parm = {}; + if (userAvatar != null) { + parm["userAvatar"] = userAvatar; + } + if (userNickname != null) { + parm["userNickname"] = userNickname; + } + if (userSex != null) { + parm["userSex"] = userSex; + } + + if (age != null) { + parm["age"] = age; + } + + if (bornYear != null) { + parm["bornYear"] = bornYear; + } + + if (bornMonth != null) { + parm["bornMonth"] = bornMonth; + } + if (bornDay != null) { + parm["bornDay"] = bornDay; + } + if (countryId != null) { + parm["countryId"] = countryId; + } + if (hobby != null) { + parm["hobby"] = hobby; + } + if (autograph != null) { + parm["autograph"] = autograph; + } + if (backgroundPhotos != null) { + parm["backgroundPhotos"] = backgroundPhotos; + } + if (personalPhotos != null) { + parm["personalPhotos"] = personalPhotos; + } + + final result = await http.put( + "2fa1d4f56bb726558904ce2a50b83f96365e62b6aa808acde7b56d2d5945fbe4", + data: parm, + fromJson: (json) => SocialChatUserProfile.fromJson(json), + ); + return result; + } + + ///user/support-relation/follow/my-list + @override + Future> followMyList({ + String? account, + String? lastId, + }) async { + Map parm = {}; + if (account != null) { + parm["account"] = account; + } + if (lastId != null) { + parm["lastId"] = lastId; + } + final result = await http.get>( + "5ee2ca437d883bcd9a4030c44b20b059984d86f34396dfa8045aa8afe71cb567bc4a9e8c4704c0f73c085e7ab50e7fdb", + queryParams: parm, + fromJson: + (json) => + (json as List).map((e) => FollowUserRes.fromJson(e)).toList(), + ); + return result; + } + + ///user/support-relation/fans/my-list + @override + Future> fansMyList({ + String? account, + String? lastId, + }) async { + Map parm = {}; + if (account != null) { + parm["account"] = account; + } + if (lastId != null) { + parm["lastId"] = lastId; + } + final result = await http.get>( + "5ee2ca437d883bcd9a4030c44b20b05995242771a17d74da900d0d3c02debf52397bb180e31856d94bf25d85eb342787", + queryParams: parm, + fromJson: + (json) => + (json as List).map((e) => FollowUserRes.fromJson(e)).toList(), + ); + return result; + } + + ///wallet/gold/this-month/asset-record + @override + Future> goldRecord({num? type, String? lastId}) async { + Map parm = {}; + if (type != null) { + parm["type"] = type; + } + if (lastId != null) { + parm["lastId"] = lastId; + } + final result = await http.get>( + "aabf121bb4c193ccceac70586aa16f3b06ad35ecd192416cde0bc922045e1dda68a9458578aa4b21fc86df1010fa2ca2", + queryParams: parm, + fromJson: + (json) => + (json as List).map((e) => SCGoldRecordRes.fromJson(e)).toList(), + ); + return result; + } + + ///user/support-relation/counter + @override + Future> userCounter(String userId) async { + Map parm = {}; + parm["userId"] = userId; + final result = await http.get>( + "5ee2ca437d883bcd9a4030c44b20b05980e9d6b90837a95599c7f32e68756428", + queryParams: parm, + fromJson: + (json) => + (json as List).map((e) => SCUserCounterRes.fromJson(e)).toList(), + ); + return result; + } + + ///app/h5/identity + @override + Future userIdentity({String? userId}) async { + Map parm = {}; + if (userId != null) { + parm["userId"] = userId; + } + final result = await http.get( + "d29121f09fa26c45b5322df6de0fc25b", + queryParams: parm, + fromJson: (json) => SCUserIdentityRes.fromJson(json), + ); + return result; + } + + ///user/user-level/consumption/exp + @override + Future userLevelConsumptionExp( + String userId, + String type, + ) async { + Map parm = {}; + parm["userId"] = userId; + parm["type"] = type; + final result = await http.get( + "9863061ae38e7d452fdd7f95840a952f2751db44c8c4787063c9ccf1dcd80366", + queryParams: parm, + fromJson: (json) => SCUserLevelExpRes.fromJson(json), + ); + return result; + } + + ///task/check/in/today + @override + Future checkInToday() async { + final result = await http.get( + "b5908b3dc914a82da088fadf8be59213143ec06ec0fc08a0d7d915f0556e3821", + fromJson: (json) => json as bool, + ); + return result; + } + + ///task/check/in/list/award + @override + Future sginListAward() async { + final result = await http.get( + "acdc80e923fd539da1401826ee3e99169b3b4b9cccf8933804239f0e070c54c7", + fromJson: (json) => SCSignInRes.fromJson(json), + ); + return result; + } + + ///task/check/in/receive + @override + Future checkInReceive(String id, String resourceGroupId) async { + Map parm = {}; + parm["id"] = id; + parm["resourceGroupId"] = resourceGroupId; + final result = await http.post( + "cd4f02cf4ef018533e882d3cbb23a6aeaeb1d976c8b96774303e69619d73e630", + data: parm, + fromJson: (json) => json as int, + ); + return result; + } + + @override + Future signInRewardStatus() async { + const path = "/go/app/sign-in-reward/status"; + debugPrint( + '[SignInReward][Request] GET $path ' + 'baseUrl=${http.dio.options.baseUrl} params={}', + ); + try { + final result = await http.get( + path, + fromJson: (json) => SCSignInRewardStatusRes.fromJson(json), + ); + debugPrint( + '[SignInReward][Response] GET $path ' + 'summary=${jsonEncode(_signInRewardStatusSummary(result))}', + ); + return result; + } catch (error) { + debugPrint('[SignInReward][Error] GET $path error=$error'); + _debugSignInRewardError('GET', path, error); + rethrow; + } + } + + @override + Future signInRewardCheckIn() async { + const path = "/go/app/sign-in-reward/check-in"; + const body = {}; + debugPrint( + '[SignInReward][Request] POST $path ' + 'baseUrl=${http.dio.options.baseUrl} body=${jsonEncode(body)}', + ); + try { + final result = await http.post( + path, + data: body, + fromJson: (json) => SCSignInRewardCheckInRes.fromJson(json), + ); + debugPrint( + '[SignInReward][Response] POST $path ' + 'summary=${jsonEncode(_signInRewardCheckInSummary(result))}', + ); + return result; + } catch (error) { + debugPrint('[SignInReward][Error] POST $path error=$error'); + _debugSignInRewardError('POST', path, error); + rethrow; + } + } + + void _debugSignInRewardError(String method, String path, Object error) { + if (error is DioException) { + final requestOptions = error.requestOptions; + final response = error.response; + debugPrint( + '[SignInReward][Dio] $method $path ' + 'type=${error.type} ' + 'message=${error.message} ' + 'uri=${requestOptions.uri}', + ); + debugPrint( + '[SignInReward][Dio] $method $path ' + 'headers=${jsonEncode(requestOptions.headers)} ' + 'query=${jsonEncode(requestOptions.queryParameters)} ' + 'data=${jsonEncode(requestOptions.data)}', + ); + debugPrint( + '[SignInReward][Dio] $method $path ' + 'statusCode=${response?.statusCode} ' + 'statusMessage=${response?.statusMessage} ' + 'response=${jsonEncode(response?.data)} ' + 'innerError=${error.error}', + ); + return; + } + + debugPrint('[SignInReward][Dio] $method $path non-dio-error=$error'); + } + + Map _signInRewardStatusSummary( + SCSignInRewardStatusRes result, + ) { + return { + 'configured': result.configured, + 'enabled': result.enabled, + 'available': result.available, + 'signedToday': result.signedToday, + 'currentStreak': result.currentStreak, + 'nextDayIndex': result.nextDayIndex, + 'cycleDays': result.cycleDays, + 'daysCount': result.days.length, + 'days': + result.days + .map( + (day) => { + 'dayIndex': day.dayIndex, + 'signed': day.signed, + 'todayTarget': day.todayTarget, + 'rewardGroupId': day.rewardGroupId, + 'rewardGroupName': day.rewardGroupName, + 'rewardItems': + day.rewardItems + .map( + (item) => { + 'id': item.id, + 'type': item.type, + 'name': item.name, + 'content': item.content, + 'quantity': item.quantity, + 'cover': item.cover, + 'remark': item.remark, + }, + ) + .toList(), + }, + ) + .toList(), + }; + } + + Map _signInRewardCheckInSummary( + SCSignInRewardCheckInRes result, + ) { + return { + 'success': result.success, + 'alreadySigned': result.alreadySigned, + 'dayIndex': result.dayIndex, + 'streakCount': result.streakCount, + 'rewardGroupId': result.rewardGroupId, + 'rewardGroupName': result.rewardGroupName, + 'status': result.status, + 'rewardItems': + result.rewardItems + .map( + (item) => { + 'id': item.id, + 'type': item.type, + 'name': item.name, + 'content': item.content, + 'quantity': item.quantity, + 'cover': item.cover, + 'remark': item.remark, + }, + ) + .toList(), + }; + } + + ///team/create + @override + Future teamCreate(String ownUserId) async { + Map parm = {}; + parm["ownUserId"] = ownUserId; + final result = await http.post( + "9d3a59e43ee9cf3729f57abc0c596005", + data: parm, + fromJson: (json) => json as bool, + ); + return result; + } + + ///public-message/page + @override + Future publicMessagePage( + String type, + num pageNo, + num pageSize, + ) async { + Map parm = {}; + parm["type"] = type; + parm["pageNo"] = pageNo; + parm["pageSize"] = pageSize; + final result = await http.get( + "38801b8e4843cf3f040b20e8e7a32554118a90740b43e354a7fdc9ac837e0671", + queryParams: parm, + fromJson: (json) => SCPublicMessagePageRes.fromJson(json), + ); + return result; + } + + ///user/friend-relation/list + @override + Future> friendList({String? lastId}) async { + Map parm = {}; + if (lastId != null) { + parm["lastId"] = lastId; + } + final result = await http.get>( + "4aff0909d268eb1d0a7f1ded14d28357d8c0811eb69bd36aaaf7bf3d8bf0e486", + queryParams: parm, + fromJson: + (json) => + (json as List) + .map((e) => MessageFriendUserRes.fromJson(e)) + .toList(), + ); + return result; + } + + ///user/friend-relation/search + @override + Future> friendSearch(String account) async { + Map parm = {}; + parm["account"] = account; + final result = await http.get>( + "4aff0909d268eb1d0a7f1ded14d28357879fc2cee9e8f2051bbaccb8bf07e372", + queryParams: parm, + fromJson: + (json) => + (json as List) + .map((e) => MessageFriendUserRes.fromJson(e)) + .toList(), + ); + return result; + } + + ///team/invite-message-process + @override + Future inviteHost(String id, String status) async { + Map parm = {}; + parm["id"] = id; + parm["status"] = status; + final result = await http.post( + "e5989162aa832581f74b9a383248e4b8317f6af14ecd57b0c1e01a5e47e7414d", + data: parm, + fromJson: (json) => json as bool, + ); + return result; + } + + ///team/bd/invite-message-process + @override + Future inviteAgent(String id, String status) async { + Map parm = {}; + parm["id"] = id; + parm["status"] = status; + final result = await http.post( + "5e44a26c2a5805a21846bf04cb67a75108fa66d1b5877cd04fb8d1761aa95547", + data: parm, + fromJson: (json) => json as bool, + ); + return result; + } + + ///team/bd/invite-bd-message-process + @override + Future inviteBD(String id, String status) async { + Map parm = {}; + parm["id"] = id; + parm["status"] = status; + final result = await http.post( + "bbdc8997a823680923efb54a9d31072eabf7f2c09434925bdc6cd2a847f93dcfba2fafbaede21817c8d7e89774331852", + data: parm, + fromJson: (json) => json as bool, + ); + return result; + } + + ///team/bd/invite-bdleader-message-process + @override + Future inviteBDLeader(String id, String status) async { + Map parm = {}; + parm["id"] = id; + parm["status"] = status; + final result = await http.post( + "bbdc8997a823680923efb54a9d31072eb14922cefad1be12ebcebd874a66585c7f7f07aa8fdbecc97b3d68d3389dd470", + data: parm, + fromJson: (json) => json as bool, + ); + return result; + } + + ///team/bd/invite-recharge-agent-message-process + @override + Future inviteRechargeAgent(String id, String status) async { + Map parm = {}; + parm["id"] = id; + parm["status"] = status; + final result = await http.post( + "771f90aeda269f6e1eb1421f4335c8bf02f5ada0ff7a70fca49e8b367fd079ffd991f48d7a7af790a9593ff2caf1f6fc", + data: parm, + fromJson: (json) => json as bool, + ); + return result; + } + + ///user/support-relation/follow/check + @override + Future followCheck(String userId) async { + Map parm = {}; + parm["userId"] = userId; + final result = await http.get( + "5ee2ca437d883bcd9a4030c44b20b059cda65c203d085b6a0dc3eb6c86372454b6de76cbe76f15fa0a33e1759219198c", + queryParams: parm, + fromJson: (json) => json as bool, + ); + return result; + } + + ///user/support-relation/follow-new + @override + Future followNew(String userId) async { + Map parm = {}; + parm["userId"] = userId; + final result = await http.post( + "5ee2ca437d883bcd9a4030c44b20b059787556c9e7c91af11f63f466fc47a7a6574aff257ce7e668d08f4caccd1c6232", + data: parm, + fromJson: (json) => json as bool, + ); + return result; + } + + ///app/v2/task/list + @override + Future> tasks() async { + final result = await http.get>( + "6e87048da643aa0388a9e46ea391daff574aff257ce7e668d08f4caccd1c6232", + fromJson: + (json) => + (json as List).map((e) => SCTaskListRes.fromJson(e)).toList(), + ); + return result; + } + + ///app/v2/task/reward + @override + Future taskReward(num taskId) async { + Map parm = {}; + parm["taskId"] = taskId; + final result = await http.get( + "0047abf8502867ed03180e3a6b505d411832ea9bebe4ec426a7036c865082475", + queryParams: parm, + fromJson: (json) => json as bool, + ); + return result; + } + + ///user/support-relation/visitor/list + @override + Future> visitorList(num pageNumber) async { + Map parm = {}; + parm["pageNumber"] = pageNumber; + final result = await http.get>( + "5ee2ca437d883bcd9a4030c44b20b05903ab400c9bf27c42312a7e75b67b25a0397bb180e31856d94bf25d85eb342787", + queryParams: parm, + fromJson: + (json) => + (json as List).map((e) => FollowUserRes.fromJson(e)).toList(), + ); + return result; + } + + ///prop/coupon/list + @override + Future propCouponList( + num size, + num current, { + int? couponType, + }) async { + Map parm = {}; + parm["size"] = size; + parm["current"] = current; + if (couponType != null) { + parm["couponType"] = couponType; + } + final result = await http.post( + "c05bb66ab1d14464aa75f1842e222ce0574aff257ce7e668d08f4caccd1c6232", + data: parm, + fromJson: (json) => SCPropCouponListRes.fromJson(json), + ); + return result; + } + + ///prop/coupon/record/list + @override + Future couponRecordList( + num size, + num current, { + int? couponType, + int? status, + }) async { + Map parm = {}; + parm["size"] = size; + parm["current"] = current; + if (couponType != null) { + parm["couponType"] = couponType; + } + if (status != null) { + parm["status"] = status; + } + final result = await http.post( + "0348972fba6d4c510c1860e435c3f68297e6790742d0344ce6b20c597ee86fd1", + data: parm, + fromJson: (json) => SCPropCouponRecordListRes.fromJson(json), + ); + return result; + } + + ///prop/coupon/use + @override + Future couponUse(String couponNo) async { + Map parm = {}; + parm["couponNo"] = couponNo; + final result = await http.post( + "6163f60d541d3361be0d3f8ef816fc1d", + data: parm, + fromJson: (json) => json as bool, + ); + return result; + } + + ///prop/coupon/create + @override + Future couponSend(String couponNo, String receiverId) async { + Map parm = {}; + parm["couponNo"] = couponNo; + parm["receiverId"] = receiverId; + final result = await http.post( + "431750258fbc9a54a3298bf431007fd56ad9a4bc80736146ebc083f857e42b4f", + data: parm, + fromJson: (json) => json as bool, + ); + return result; + } + + ///user/badge/own/list + @override + Future> badgeOwnList(String type) async { + Map parm = {}; + parm["type"] = type; + final result = await http.get>( + "2d234c6012ceaca8dbd3923bb17b2adaf13e23fb57376accca26ee78f1baa860", + queryParams: parm, + fromJson: + (json) => (json as List).map((e) => WearBadge.fromJson(e)).toList(), + ); + return result; + } + + ///user/badge/toggle + @override + Future badgeToggle(String badgeId) async { + Map parm = {}; + parm["badgeId"] = badgeId; + final result = await http.post( + "84169ec3c928dde3a22cb4b7b6ae95c31e1cf9b945681bdfb3d4cf7a5ecfc943", + data: parm, + fromJson: (json) => json as bool, + ); + return result; + } + + ///user-violation/handle + @override + Future userViolationHandle( + String userId, + int violationType, + int operationType, + String description, { + List? imageUrls, + }) async { + Map parm = {}; + parm["userId"] = userId; + parm["violationType"] = violationType; + parm["operationType"] = operationType; + parm["description"] = description; + if (imageUrls != null && imageUrls.isNotEmpty) { + parm["screenshotUrls"] = imageUrls; + } + final result = await http.post( + "cc84151e5fba2824710e0645046729a06f894acdcdbac7ccb7e88e9d69ee3eff", + data: parm, + fromJson: (json) => SCViolationHandleRes.fromJson(json), + ); + return result; + } + + ///user/cp-relationship/create-apply + @override + Future cpRelationshipSendApply(String acceptApplyUserId) async { + Map parm = {}; + parm["acceptApplyUserId"] = acceptApplyUserId; + final result = await http.post( + "b06a43ca828553e84580a84da4a3af6135e967dbd0d9edde6478905c4b167fd37b53dae821c941c8c13570fbc26665ba", + data: parm, + fromJson: (json) => json as bool, + ); + return result; + } + + ///user/cp-relationship/process-apply + @override + Future cpRelationshipProcessApply(String applyId, bool agree) async { + Map parm = {}; + parm["applyId"] = applyId; + parm["agree"] = agree; + final result = await http.post( + "b06a43ca828553e84580a84da4a3af61cb64264b44425ec78a0115bfc976a827fd57dd4d0233d969f8991e901a14e144", + data: parm, + fromJson: (json) => json as bool, + ); + return result; + } + + ///user/cp-relationship/dismiss-apply + @override + Future cpRelationshipDismissApply(String cpUserId) async { + Map parm = {}; + parm["cpUserId"] = cpUserId; + final result = await http.get( + "b06a43ca828553e84580a84da4a3af6147b0e44e9311c7615dee77b6c4c425a1fd57dd4d0233d969f8991e901a14e144", + queryParams: parm, + fromJson: (json) => json as bool, + ); + return result; + } + + ///user/friend-relation/check + @override + Future friendRelationCheck(String userId) async { + Map parm = {}; + parm["userId"] = userId; + final result = await http.get( + "4aff0909d268eb1d0a7f1ded14d28357691f1c364e338d7fc3c50cf21be0f908", + queryParams: parm, + fromJson: (json) => json as bool, + ); + return result; + } + + ///user/red-packet/create + @override + Future userRedPacketSend( + String receiverUserId, + String totalAmount, + ) async { + Map parm = {}; + parm["receiverUserId"] = receiverUserId; + parm["totalAmount"] = totalAmount; + final result = await http.post( + "69585024cc7ee090d1e29ff7ca160a45f01ca103e12cc332b59b5a8e39c778ec", + data: parm, + fromJson: (json) => SCUserRedPacketSendRes.fromJson(json), + ); + return result; + } + + ///user/red-packet/detail + @override + Future userRedPacketDetail(String packetId) async { + Map parm = {}; + parm["packetId"] = packetId; + final result = await http.get( + "69585024cc7ee090d1e29ff7ca160a457f342deecb1b83d2d8429c59146f10f0", + queryParams: parm, + fromJson: (json) => SCUserRedPacketSendRes.fromJson(json), + ); + return result; + } + + ///user/red-packet/grab + @override + Future userRedPacketGrab(String packetId) async { + Map parm = {}; + parm["packetId"] = packetId; + final result = await http.post( + "69585024cc7ee090d1e29ff7ca160a450b2a61d0ce4f3f4d50875dcc95b640af", + data: parm, + fromJson: (json) => SCUserRedPacketGrabRes.fromJson(json), + ); + return result; + } + + ///user/blacklist/list + @override + Future> userBlacklistList({ + String? account, + String? lastId, + }) async { + Map parm = {}; + if (account != null) { + parm["account"] = account; + } + if (lastId != null) { + parm["lastId"] = lastId; + } + final result = await http.get>( + "62bd6154ca9eb9207f3e50294ed18035f13e23fb57376accca26ee78f1baa860", + queryParams: parm, + fromJson: + (json) => + (json as List) + .map((e) => MessageFriendUserRes.fromJson(e)) + .toList(), + ); + return result; + } + + ///user/blacklist/check + @override + Future blacklistCheck(String shieldUserId) async { + Map parm = {}; + parm["shieldUserId"] = shieldUserId; + final result = await http.post( + "66644b702102d48f4284444b05b1200deda65d2aec525e95d29625cf93fa9e45", + data: parm, + fromJson: (json) => json as bool, + ); + return result; + } + + ///user/blacklist + @override + Future addUserBlacklist(String shieldUserId) async { + Map parm = {}; + parm["shieldUserId"] = shieldUserId; + final result = await http.post( + "3f6e2326c10aaed6e637ac0d78a20a3b", + data: parm, + fromJson: (json) => json as bool, + ); + return result; + } + + ///user/blacklist/cancel + @override + Future deleteUserBlacklist(String shieldUserId) async { + Map parm = {}; + parm["shieldUserId"] = shieldUserId; + final result = await http.post( + "66644b702102d48f4284444b05b1200d13afc33ba8e2ca51c7245d9201b4569d", + data: parm, + fromJson: (json) => json as bool, + ); + return result; + } + + ///auth/logout + @override + Future logoutAccount() async { + final result = await http.delete( + "814a34263274ff501f4ca9ae76c4aae3", + fromJson: (json) => json as bool, + ); + return result; + } + + ///user/vip/ability/update + @override + Future userVipAbilityUpdate({ + String? contactMode, + bool? kickPrevention, + bool? mysteriousInvisibility, + bool? antiBlock, + }) async { + Map parm = {}; + if (contactMode != null) { + parm["contactMode"] = contactMode; + } + if (kickPrevention != null) { + parm["kickPrevention"] = kickPrevention; + } + if (mysteriousInvisibility != null) { + parm["mysteriousInvisibility"] = mysteriousInvisibility; + } + if (antiBlock != null) { + parm["antiBlock"] = antiBlock; + } + final result = await http.post( + "9bad890ecd3a153658cbe38367fcc46f3db9e152c7701ff2e5e1d4261f763895", + data: parm, + fromJson: (json) => json as bool, + ); + return result; + } +} diff --git a/lib/ui_kit/widgets/daily_sign_in/daily_sign_in_dialog.dart b/lib/ui_kit/widgets/daily_sign_in/daily_sign_in_dialog.dart index b3965e5..9ac33c7 100644 --- a/lib/ui_kit/widgets/daily_sign_in/daily_sign_in_dialog.dart +++ b/lib/ui_kit/widgets/daily_sign_in/daily_sign_in_dialog.dart @@ -5,7 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:yumi/app_localizations.dart'; -import 'package:yumi/shared/business_logic/models/res/sc_sign_in_res.dart'; +import 'package:yumi/shared/business_logic/models/res/sc_sign_in_reward_res.dart'; import 'package:yumi/shared/data_sources/sources/repositories/sc_user_repository_impl.dart'; import 'package:yumi/shared/tools/sc_loading_manager.dart'; import 'package:yumi/ui_kit/components/sc_debounce_widget.dart'; @@ -22,8 +22,6 @@ class DailySignInDialogItem { required this.isFinalDay, this.subtitle = '', this.cover = '', - this.rewardId = '', - this.resourceGroupId = '', }); final int day; @@ -32,13 +30,8 @@ class DailySignInDialogItem { final String cover; final DailySignInRewardStatus status; final bool isFinalDay; - final String rewardId; - final String resourceGroupId; - bool get canClaim => - status == DailySignInRewardStatus.current && - rewardId.isNotEmpty && - resourceGroupId.isNotEmpty; + bool get canClaim => status == DailySignInRewardStatus.current; DailySignInDialogItem copyWith({ int? day, @@ -47,8 +40,6 @@ class DailySignInDialogItem { String? cover, DailySignInRewardStatus? status, bool? isFinalDay, - String? rewardId, - String? resourceGroupId, }) { return DailySignInDialogItem( day: day ?? this.day, @@ -57,8 +48,6 @@ class DailySignInDialogItem { cover: cover ?? this.cover, status: status ?? this.status, isFinalDay: isFinalDay ?? this.isFinalDay, - rewardId: rewardId ?? this.rewardId, - resourceGroupId: resourceGroupId ?? this.resourceGroupId, ); } } @@ -132,42 +121,41 @@ class DailySignInDialogData { ); } - factory DailySignInDialogData.fromLegacy({ - required SCSignInRes signInRes, - required bool checkedToday, + factory DailySignInDialogData.fromStatus({ + required SCSignInRewardStatusRes statusRes, }) { - final rewards = List.from( - signInRes.rewards ?? const [], - )..sort( - (left, right) => (left.rule?.sort ?? 0).compareTo(right.rule?.sort ?? 0), - ); - - final signedDays = (signInRes.days ?? 0).toInt().clamp(0, 7); - final currentDay = checkedToday ? -1 : math.min(signedDays + 1, 7); + final sortedDays = List.from(statusRes.days) + ..sort((left, right) => left.dayIndex.compareTo(right.dayIndex)); + final dayMap = { + for (final day in sortedDays) day.dayIndex: day, + }; final items = List.generate(7, (index) { final day = index + 1; - final reward = index < rewards.length ? rewards[index] : null; + final rewardDay = dayMap[day]; final status = - day <= signedDays + rewardDay?.signed == true ? DailySignInRewardStatus.claimed - : day == currentDay + : !statusRes.signedToday && + ((rewardDay?.todayTarget ?? false) || + statusRes.nextDayIndex == day) ? DailySignInRewardStatus.current : DailySignInRewardStatus.pending; return DailySignInDialogItem( day: day, - title: _resolveTitle(reward), - subtitle: _resolveSubtitle(reward), - cover: _resolveCover(reward), + title: _resolveTitle(rewardDay), + subtitle: _resolveSubtitle(rewardDay), + cover: _resolveCover(rewardDay), status: status, isFinalDay: day == 7, - rewardId: reward?.rule?.id?.trim() ?? '', - resourceGroupId: reward?.rule?.resourceGroupId?.trim() ?? '', ); }); - return DailySignInDialogData(items: items, checkedToday: checkedToday); + return DailySignInDialogData( + items: items, + checkedToday: statusRes.signedToday, + ); } DailySignInDialogData copyWith({ @@ -180,12 +168,12 @@ class DailySignInDialogData { ); } - static ActivityRewardProps? _firstRewardProp(Rewards? reward) { - final props = reward?.propsGroup?.activityRewardProps; - if (props == null || props.isEmpty) { + static SCSignInRewardItem? _firstRewardItem(SCSignInRewardDay? rewardDay) { + final rewardItems = rewardDay?.rewardItems; + if (rewardItems == null || rewardItems.isEmpty) { return null; } - return props.first; + return rewardItems.first; } static String _pickFirstNonEmpty(List values, String fallback) { @@ -198,38 +186,32 @@ class DailySignInDialogData { return fallback; } - static String _resolveTitle(Rewards? reward) { - final prop = _firstRewardProp(reward); + static String _resolveTitle(SCSignInRewardDay? rewardDay) { + final rewardItem = _firstRewardItem(rewardDay); return _pickFirstNonEmpty([ - reward?.propsGroup?.name, - prop?.content, - prop?.remark, - prop?.detailType, + rewardItem?.name, + rewardItem?.content, + rewardDay?.rewardGroupName, + rewardItem?.type, + rewardItem?.remark, ], 'Profile Frame'); } - static String _resolveSubtitle(Rewards? reward) { - final prop = _firstRewardProp(reward); - final quantity = prop?.quantity; - if (quantity != null && quantity > 1) { - return 'x${quantity.toInt()}'; - } - - final amount = prop?.amount; - if (amount != null && amount > 0) { - return amount == amount.toInt() ? '${amount.toInt()}' : '$amount'; + static String _resolveSubtitle(SCSignInRewardDay? rewardDay) { + final rewardItem = _firstRewardItem(rewardDay); + if ((rewardItem?.quantity ?? 0) > 1) { + return 'x${rewardItem!.quantity}'; } final textValue = _pickFirstNonEmpty([ - prop?.type, - prop?.detailType, - prop?.remark, + rewardItem?.remark, + rewardItem?.type, ], ''); return textValue == 'Profile Frame' ? '' : textValue; } - static String _resolveCover(Rewards? reward) { - return _firstRewardProp(reward)?.cover?.trim() ?? ''; + static String _resolveCover(SCSignInRewardDay? rewardDay) { + return _firstRewardItem(rewardDay)?.cover.trim() ?? ''; } } @@ -277,12 +259,19 @@ class _DailySignInDialogState extends State { void initState() { super.initState(); _data = widget.data; + debugPrint( + '[SignInReward][Dialog] init ' + 'checkedToday=${_data.checkedToday} ' + 'currentDay=${_data.currentItem?.day ?? 0} ' + 'items=${_debugItemsSummary(_data.items)}', + ); } Future _handleCheckIn() async { if (_isSubmitting) { return; } + final l10n = SCAppLocalizations.of(context)!; if (_data.checkedToday) { SmartDialog.dismiss(tag: DailySignInDialog.dialogTag); return; @@ -298,25 +287,28 @@ class _DailySignInDialogState extends State { _isSubmitting = true; }); SCLoadingManager.show(); + debugPrint( + '[SignInReward][Dialog] tap check-in ' + 'currentDay=${currentItem.day}', + ); try { - await SCAccountRepository().checkInReceive( - currentItem.rewardId, - currentItem.resourceGroupId, - ); + final checkInResult = await SCAccountRepository().signInRewardCheckIn(); + if (!checkInResult.isClaimed) { + throw Exception(l10n.thisFeatureIsCurrentlyUnavailable); + } DailySignInDialogData latestData; try { - final result = await Future.wait([ - SCAccountRepository().checkInToday(), - SCAccountRepository().sginListAward(), - ]); - latestData = DailySignInDialogData.fromLegacy( - signInRes: result[1] as SCSignInRes, - checkedToday: result[0] as bool, - ); + debugPrint('[SignInReward][Dialog] reload status after check-in'); + final latestStatus = await SCAccountRepository().signInRewardStatus(); + latestData = DailySignInDialogData.fromStatus(statusRes: latestStatus); } catch (_) { - latestData = _markCurrentItemAsClaimed(_data); + debugPrint( + '[SignInReward][Dialog] reload status failed, fallback to local update ' + 'dayIndex=${checkInResult.dayIndex}', + ); + latestData = _markDayAsClaimed(_data, checkInResult.dayIndex); } SCLoadingManager.hide(); @@ -326,9 +318,19 @@ class _DailySignInDialogState extends State { setState(() { _data = latestData; }); - SCTts.show(SCAppLocalizations.of(context)!.receiveSucc); + debugPrint( + '[SignInReward][Dialog] check-in success ' + 'alreadySigned=${checkInResult.alreadySigned} ' + 'dayIndex=${checkInResult.dayIndex} ' + 'checkedToday=${latestData.checkedToday}', + ); + SCTts.show( + checkInResult.alreadySigned ? l10n.signedin : l10n.receiveSucc, + ); + SmartDialog.dismiss(tag: DailySignInDialog.dialogTag); } catch (error) { SCLoadingManager.hide(); + debugPrint('[SignInReward][Dialog] check-in failed error=$error'); if (!mounted) { return; } @@ -345,12 +347,17 @@ class _DailySignInDialogState extends State { } } - DailySignInDialogData _markCurrentItemAsClaimed(DailySignInDialogData data) { + DailySignInDialogData _markDayAsClaimed( + DailySignInDialogData data, + int dayIndex, + ) { return data.copyWith( checkedToday: true, items: data.items.map((item) { - if (item.status == DailySignInRewardStatus.current) { + if ((dayIndex > 0 && item.day == dayIndex) || + (dayIndex <= 0 && + item.status == DailySignInRewardStatus.current)) { return item.copyWith(status: DailySignInRewardStatus.claimed); } return item; @@ -358,6 +365,15 @@ class _DailySignInDialogState extends State { ); } + String _debugItemsSummary(List items) { + return items + .map( + (item) => + '{day:${item.day},title:${item.title},status:${item.status.name}}', + ) + .join(','); + } + @override Widget build(BuildContext context) { final screenWidth = MediaQuery.sizeOf(context).width; diff --git a/local_packages/flutter_foreground_task-9.1.0/example/devtools_options.yaml b/local_packages/flutter_foreground_task-9.1.0/example/devtools_options.yaml new file mode 100644 index 0000000..fa0b357 --- /dev/null +++ b/local_packages/flutter_foreground_task-9.1.0/example/devtools_options.yaml @@ -0,0 +1,3 @@ +description: This file stores settings for Dart & Flutter DevTools. +documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states +extensions: diff --git a/需求进度.md b/需求进度.md index 97a52d4..03fee58 100644 --- a/需求进度.md +++ b/需求进度.md @@ -22,7 +22,7 @@ ## 已完成模块 - 已按 2026-04-20 最新首页视觉需求,为 Party 房间列表前 3 个房卡接入新的本地排名边框 SVGA:桌面“房间排序前三的框”中的 3 份素材已导入工程并挂到首页房卡最上层,仅作用于当前列表前 3 项,其余房卡保持原样;后续又继续为前三房卡底部信息区补了横向与底部安全区,避免外扩边框直接压住国旗、房名和在线人数。同时 `Me` 板块里的 `Recent / Followed` tab 已继续对齐上方首页 tab 的斜体字样式,并移除了点击时的波浪反馈。 - 已按 2026-04-20 最新房间联调继续修正房主在自己房间里的麦位操作回归:当前房主/管理员点击自己所在麦位时,不再被“直接打开资料卡”逻辑短路,会重新回到底部麦位菜单,从而正常看到自己可用的上下麦/禁麦操作;同时上麦、下麦、禁麦、解禁、锁麦、解锁这些动作在接口成功后会立即回写本地麦位状态,并主动补拉一次最新麦位列表,减少房主端自己操作后 UI 状态延迟或短暂错乱。 -- 已按 2026-04-20 最新确认继续完成 `Wallet -> Recharge` 的 MiFaPay 真链路接入:页面仍保持“原页面结构 + 局部新增”的方案,只在原充值页白色内容区顶部新增 `Recharge methods`,且该标题已改成项目常见的土豪金色;`Google Pay / Apple Pay` 继续保留原生内购列表,`MiFaPay` 已从占位切成真实接口驱动,进入页面会拉 `/order/web/pay/country`、`/order/web/pay/commodity`,底部弹窗会展示真实商品与支付渠道,确认后调用 `/order/web/pay/recharge` 下单并拉起 MiFaPay H5 WebView。用户关闭收银台返回 App 后,当前会立即刷新钱包余额并轮询最新金币额;命中到账后会直接提示购买成功,避免只停留在“支付确认中”。 +- 已按 2026-04-20 最新调整撤掉 `Wallet -> Recharge` 中新增的 MiFaPay 第三方支付 UI 与页面逻辑:当前充值页仅保留原生 `Google Pay / Apple Pay` 入口与商品列表,`Recharge methods` 区域也已收敛为单一原生支付卡片;此前接入的 MiFaPay 方法选择、底部弹窗、H5 收银台页以及对应页面级状态管理已从现有充值链路移除,避免继续对当前版本产生影响。 - 已按 2026-04-18 联调要求继续收口幸运礼物链路:项目默认 API host 已临时切到 `http://192.168.110.43:1100/` 方便直连测试环境;`/gift/give/lucky-gift` 请求体也已补齐为最新结构,除原有 `giftId/quantity/roomId/acceptUserIds/checkCombo` 外,会稳定携带 `gameId: null`、`accepts: []`、`dynamicContentId: null`、`songId: null` 这几组字段,便于和当前后端参数定义保持一致。 - 已继续补齐 `GAME_LUCKY_GIFT` 的 socket 播报与中奖动效:房间群消息收到该类型后,现在会统一落聊天室中奖消息、奖励弹层队列与发送者余额回写,不再只在 `3x+` 时才触发顶部奖励动画;同时全局飘窗已改为按服务端 `globalNews` 字段决定是否展示,避免再用前端本地倍率硬编码去猜。 - 已按最新 UI 口径重排幸运礼物中奖展示:顶部 `LuckGiftNomorAnimWidget` 不再叠加大头像、倍率和奖励框,只在“单个礼物倍率 `> 10x`”或“单次中奖金币 `> 5000`”时负责播全屏 `luck_gift_reward_burst.svga`;原本的 `luck_gift_reward_frame.svga` 已改挂到房间礼物播报条最右侧,并在框内显示 `+formattedAwardAmount`,金额文案直接复用此前大头像下方那一份中奖金币额。 @@ -164,9 +164,6 @@ - `需求进度.md` - `lib/main.dart` - `lib/modules/wallet/recharge/recharge_page.dart` -- `lib/modules/wallet/recharge/recharge_method_bottom_sheet.dart` -- `lib/modules/wallet/recharge/mifa_pay_webview_page.dart` -- `lib/services/payment/mifa_pay_manager.dart` - `lib/shared/business_logic/models/res/sc_mifa_pay_res.dart` - `lib/shared/business_logic/repositories/config_repository.dart` - `lib/shared/data_sources/sources/repositories/sc_config_repository_imp.dart`