diff --git a/assets/flutter_i18n/en.json b/assets/flutter_i18n/en.json index 0c17fa04..4a862b33 100644 --- a/assets/flutter_i18n/en.json +++ b/assets/flutter_i18n/en.json @@ -447,5 +447,6 @@ "already_synced_ring": "Blueberry Ring #{0}: Already synced. ℹī¸", "data_synced_successfully_ring": "Blueberry Ring #{0}: Data synced successfully. ✅", "data_syncing_failed": "Blueberry Ring #{0}: Data syncing process failed. ❌", - "blueberry_hooks": "Blueberry hooks" + "blueberry_hooks": "Blueberry hooks", + "message": "Message" } \ No newline at end of file diff --git a/lib/core/src/background_process/dapp_hooks_service.dart b/lib/core/src/background_process/dapp_hooks_service.dart index 744daede..c2670c05 100644 --- a/lib/core/src/background_process/dapp_hooks_service.dart +++ b/lib/core/src/background_process/dapp_hooks_service.dart @@ -91,7 +91,7 @@ class DAppHooksService { } } - static void blueberryAutoSyncServiceCallBackDispatcherForeground( + static void blueberryAutoSyncServiceCallBackDispatcherForeground( String taskId) async { try { await loadProviders(); @@ -113,18 +113,18 @@ class DAppHooksService { final isLoggedIn = authUseCase.loggedIn; final account = accountUseCase.account.value; // final serviceEnabled = dappHooksData.enabled; - final minerHooksEnabled = dappHooksData.minerHooks.enabled; - final minerHooksTime = dappHooksData.minerHooks.time; - final selectedMiners = dappHooksData.minerHooks.selectedMiners; + final autoSyncEnabled = dappHooksData.blueberryRingHooks.enabled; + final ringHooksTime = dappHooksData.blueberryRingHooks.time; + final selectedRings = dappHooksData.blueberryRingHooks.selectedRings; // Make sure user is logged in - if (isLoggedIn && MXCChains.isMXCChains(chainId) && minerHooksEnabled) { + if (isLoggedIn && MXCChains.isMXCChains(chainId) && autoSyncEnabled) { await AXSNotification() .setupFlutterNotifications(shouldInitFirebase: false); - await dAppHooksUseCase.executeMinerAutoClaim( + await dAppHooksUseCase.syncBlueberryRingSync( account: account!, - selectedMinerListId: selectedMiners, - minerAutoClaimTime: minerHooksTime); + selectedRingsListId: selectedRings, + ringAutoSyncTime: ringHooksTime); BackgroundFetch.finish(taskId); } else { // terminate background fetch diff --git a/lib/core/src/providers/providers_use_cases.dart b/lib/core/src/providers/providers_use_cases.dart index 73539b21..8f1ad66c 100644 --- a/lib/core/src/providers/providers_use_cases.dart +++ b/lib/core/src/providers/providers_use_cases.dart @@ -146,6 +146,7 @@ final Provider dAppHooksUseCaseProvider = Provider( ), ref.watch(errorUseCaseProvider), ref.watch(contextLessTranslationUseCaseProvider), + ref.watch(blueberryRingBackgroundSyncUseCase), ), ); @@ -286,3 +287,15 @@ final Provider ref.watch(contextLessTranslationUseCaseProvider), ), ); + +final Provider + blueberryRingBackgroundSyncUseCase = Provider( + (ref) => BlueberryRingBackgroundSyncUseCase( + ref.watch(web3RepositoryProvider), + ref.watch(chainConfigurationUseCaseProvider), + ref.watch(bluetoothUseCaseProvider), + ref.watch(blueberryRingUseCaseProvider), + ref.watch(accountUseCaseProvider), + ref.watch(contextLessTranslationUseCaseProvider), + ), +); diff --git a/lib/features/common/contract/token_contract_use_case.dart b/lib/features/common/contract/token_contract_use_case.dart index 1839a9b7..16b98567 100644 --- a/lib/features/common/contract/token_contract_use_case.dart +++ b/lib/features/common/contract/token_contract_use_case.dart @@ -269,6 +269,11 @@ class TokenContractUseCase extends ReactiveUseCase { .getTokenTransferData(tokenHash, toAddress, amount); } + String signMessage({required String privateKey, required String message}) { + return _repository.tokenContract + .signMessage(privateKey: privateKey, message: message); + } + String signTypedMessage({required String privateKey, required String data}) { return _repository.tokenContract .signTypedMessage(privateKey: privateKey, data: data); diff --git a/lib/features/common/packages/bluetooth/blueberry_ring/domain/blueberry_ring_bckground_sync_use_case.dart b/lib/features/common/packages/bluetooth/blueberry_ring/domain/blueberry_ring_background_sync_use_case.dart similarity index 65% rename from lib/features/common/packages/bluetooth/blueberry_ring/domain/blueberry_ring_bckground_sync_use_case.dart rename to lib/features/common/packages/bluetooth/blueberry_ring/domain/blueberry_ring_background_sync_use_case.dart index a829071b..b12c42ce 100644 --- a/lib/features/common/packages/bluetooth/blueberry_ring/domain/blueberry_ring_bckground_sync_use_case.dart +++ b/lib/features/common/packages/bluetooth/blueberry_ring/domain/blueberry_ring_background_sync_use_case.dart @@ -8,8 +8,8 @@ import 'package:datadashwallet/features/settings/subfeatures/chain_configuration import '../../../../../../app/logger.dart'; -class BlueberryRingBackgroundNotificationsUseCase extends ReactiveUseCase { - BlueberryRingBackgroundNotificationsUseCase( +class BlueberryRingBackgroundSyncUseCase extends ReactiveUseCase { + BlueberryRingBackgroundSyncUseCase( this._repository, this._chainConfigurationUseCase, this._bluetoothUseCase, @@ -30,8 +30,8 @@ class BlueberryRingBackgroundNotificationsUseCase extends ReactiveUseCase { _contextLessTranslationUseCase.translate(key); - Future sendSyncTransaction({ - required BlueberryRingMiner ring, + Future syncRings({ + required List selectedRingsListId, required Account account, required void Function(String title, String? text) showNotification, required String Function( @@ -39,7 +39,26 @@ class BlueberryRingBackgroundNotificationsUseCase extends ReactiveUseCase { ) translate, }) async { + // Get miner from cache + // for (String ring in selectedRings) { + + // } // Get rings list + // Get the data from contract +// async function arrayFilterDate(array: T[], date?: number) { +// if (!date) +// return array +// return array.filter((item: any) => item.date > (date || 0)) as T[] +// } +// arrayFilterDate(arr, detail.steps.at(-1)?.date) +// List arrayFilterDate(List array, {int? date}) { +// if (date == null) return array; + +// return array.where((item) { +// var itemDate = (item as dynamic).date; // Use 'dynamic' to access the 'date' property +// return itemDate > (date ?? 0); +// }).toList(); +// } // showNotification( // translate('no_token_to_claim_miner') @@ -51,27 +70,29 @@ class BlueberryRingBackgroundNotificationsUseCase extends ReactiveUseCase { // already_synced_ring // data_synced_successfully_ring // data_syncing_failed - final memo = await fetchRingData(); + // final memo = await fetchRingData(); - final postClaimRequest = PostClaimRequestModel( - sncode: ring.sncode, - sender: account.address, - ); - final postClaimResponse = await _repository.blueberryRingRepository.postClaim( - postClaimRequest, - ); - - final txSig = await _repository.blueberryRingRepository.sendSyncTransaction(account.privateKey, ring, postClaimResponse, memo); - - // showNotification( - // translate('no_token_to_claim_miner') - // .replaceFirst('{0}', miner.mep1004TokenId!), - // null, + // final postClaimRequest = PostClaimRequestModel( + // sncode: ring.sncode, + // sender: account.address, + // ); + // final postClaimResponse = await _repository.blueberryRingRepository.postClaim( + // postClaimRequest, // ); + // final txSig = await _repository.blueberryRingRepository.sendSyncTransaction(account.privateKey, ring, postClaimResponse, memo); + // // showNotification( + // // translate('no_token_to_claim_miner') + // // .replaceFirst('{0}', miner.mep1004TokenId!), + // // null, + // // ); + + return true; } + Future syncRing(BlueberryRingMiner ring) async{} + Future fetchRingData() async { collectLog('fetchRingData'); diff --git a/lib/features/common/packages/bluetooth/blueberry_ring/domain/domain.dart b/lib/features/common/packages/bluetooth/blueberry_ring/domain/domain.dart index 0453b11d..01bb0256 100644 --- a/lib/features/common/packages/bluetooth/blueberry_ring/domain/domain.dart +++ b/lib/features/common/packages/bluetooth/blueberry_ring/domain/domain.dart @@ -1,3 +1,4 @@ export 'blueberry_repository.dart'; export 'blueberry_ring_use_case.dart'; export 'blueberry_ring_background_notifications_use_case.dart'; +export 'blueberry_ring_background_sync_use_case.dart'; diff --git a/lib/features/dapps/subfeatures/open_dapp/open_dapp_presenter.dart b/lib/features/dapps/subfeatures/open_dapp/open_dapp_presenter.dart index 94959bfc..25ecd41f 100644 --- a/lib/features/dapps/subfeatures/open_dapp/open_dapp_presenter.dart +++ b/lib/features/dapps/subfeatures/open_dapp/open_dapp_presenter.dart @@ -165,6 +165,21 @@ class OpenDAppPresenter extends CompletePresenter { return res.hash; } + String? _signMessage( + String hexData, + ) { + loading = true; + try { + final res = _tokenContractUseCase.signMessage( + privateKey: state.account!.privateKey, message: hexData); + return res; + } catch (e, s) { + addError(e, s); + } finally { + loading = false; + } + } + String? _signTypedMessage( String hexData, ) { @@ -410,6 +425,38 @@ class OpenDAppPresenter extends CompletePresenter { void signPersonalMessage() {} + void signMessage({ + required Map object, + required VoidCallback cancel, + required Function(String hash) success, + }) async { + final hexData = object['data'] as String; + String message = MXCType.hexToString(hexData); + int chainId = state.network!.chainId; + String name = state.network!.symbol; + + try { + final result = await showSignMessageDialog( + context!, + title: translate('signature_request')!, + message: message, + networkName: '$name ($chainId)', + ); + + if (result != null && result) { + final hash = _signMessage( + hexData, + ); + if (hash != null) success.call(hash); + } else { + cancel.call(); + } + } catch (e, s) { + cancel.call(); + addError(e, s); + } + } + void signTypedMessage({ required Map object, required VoidCallback cancel, @@ -740,7 +787,6 @@ class OpenDAppPresenter extends CompletePresenter { Future> handleBluetoothRemoteGATTServerConnect( Map data) async { collectLog('handleBluetoothRemoteGATTServerConnect : $data'); - await _bluetoothUseCase.connectionHandler(state.selectedScanResult!.device); return BluetoothRemoteGATTServer( diff --git a/lib/features/dapps/subfeatures/open_dapp/widgets/message_info.dart b/lib/features/dapps/subfeatures/open_dapp/widgets/message_info.dart new file mode 100644 index 00000000..efac3123 --- /dev/null +++ b/lib/features/dapps/subfeatures/open_dapp/widgets/message_info.dart @@ -0,0 +1,78 @@ +import 'package:datadashwallet/common/common.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:mxc_ui/mxc_ui.dart'; + +import '../open_dapp_presenter.dart'; + +class MessageInfo extends ConsumerWidget { + const MessageInfo({ + Key? key, + required this.networkName, + required this.message, + this.onTap, + }) : super(key: key); + + final String networkName; + final String message; + final VoidCallback? onTap; + + @override + Widget build(BuildContext context, WidgetRef ref) { + final presenter = ref.read(openDAppPageContainer.actions); + return Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 6), + child: Column( + children: [ + titleItem(context), + messageItem(context, presenter, message), + ], + ), + ), + const SizedBox(height: 8), + signButton(context), + ], + ); + } + + Widget signButton(BuildContext context) { + String titleText = 'sign'; + AxsButtonType type = AxsButtonType.primary; + + return MxcButton.primary( + key: const ValueKey('signButton'), + size: AxsButtonSize.xl, + title: FlutterI18n.translate(context, titleText), + type: type, + onTap: () { + if (onTap != null) onTap!(); + Navigator.of(context).pop(true); + }, + ); + } + + Widget titleItem(BuildContext context) { + return Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + networkName, + style: FontTheme.of(context).body2.secondary(), + softWrap: true, + ), + const SizedBox(height: 4), + ], + ) + ], + ); + } + + Widget messageItem(BuildContext context, OpenDAppPresenter presenter, String message) { + return SingleLineInfoItem(title: FlutterI18n.translate(context, 'message'), value: message); + } +} diff --git a/lib/features/dapps/subfeatures/open_dapp/widgets/sign_message_bottom_sheet.dart b/lib/features/dapps/subfeatures/open_dapp/widgets/sign_message_bottom_sheet.dart new file mode 100644 index 00000000..74169c30 --- /dev/null +++ b/lib/features/dapps/subfeatures/open_dapp/widgets/sign_message_bottom_sheet.dart @@ -0,0 +1,52 @@ +import 'package:flutter/material.dart'; +import 'package:mxc_ui/mxc_ui.dart'; + +import 'message_info.dart'; + +Future showSignMessageDialog( + BuildContext context, { + String? title, + required String networkName, + required String message, + VoidCallback? onTap, +}) { + return showModalBottomSheet( + context: context, + useRootNavigator: true, + isScrollControlled: true, + isDismissible: false, + useSafeArea: true, + backgroundColor: Colors.transparent, + builder: (BuildContext context) => Container( + padding: const EdgeInsets.only(left: 16, right: 16, top: 0, bottom: 44), + decoration: BoxDecoration( + color: ColorsTheme.of(context).screenBackground, + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(20), + topRight: Radius.circular(20), + ), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + MxcAppBarEvenly.title( + titleText: title ?? '', + action: Container( + alignment: Alignment.centerRight, + child: InkWell( + child: const Icon(Icons.close), + onTap: () => Navigator.of(context).pop(false), + ), + ), + ), + MessageInfo( + message: message, + networkName: networkName, + onTap: onTap, + ), + const SizedBox(height: 10), + ], + ), + ), + ); +} diff --git a/lib/features/dapps/subfeatures/open_dapp/widgets/widgets.dart b/lib/features/dapps/subfeatures/open_dapp/widgets/widgets.dart index acbf5eb8..d3d1af6a 100644 --- a/lib/features/dapps/subfeatures/open_dapp/widgets/widgets.dart +++ b/lib/features/dapps/subfeatures/open_dapp/widgets/widgets.dart @@ -10,3 +10,5 @@ export 'transaction_dialog.dart'; export 'transaction_info.dart'; export 'typed_message_bottom_sheet.dart'; export 'typed_message_info.dart'; +export 'message_info.dart'; +export 'sign_message_bottom_sheet.dart'; diff --git a/lib/features/settings/subfeatures/dapp_hooks/domain/dapp_hooks_use_case.dart b/lib/features/settings/subfeatures/dapp_hooks/domain/dapp_hooks_use_case.dart index 73eeb576..dcd09e8d 100644 --- a/lib/features/settings/subfeatures/dapp_hooks/domain/dapp_hooks_use_case.dart +++ b/lib/features/settings/subfeatures/dapp_hooks/domain/dapp_hooks_use_case.dart @@ -18,13 +18,15 @@ import 'dapp_hooks_repository.dart'; class DAppHooksUseCase extends ReactiveUseCase { DAppHooksUseCase( - this._repository, - this._chainConfigurationUseCase, - this._tokenContractUseCase, - this._minerUseCase, - this._accountUseCase, - this._errorUseCase, - this._contextLessTranslationUseCase) { + this._repository, + this._chainConfigurationUseCase, + this._tokenContractUseCase, + this._minerUseCase, + this._accountUseCase, + this._errorUseCase, + this._contextLessTranslationUseCase, + this._blueberryRingBackgroundSyncUseCase, + ) { initialize(); } @@ -35,6 +37,7 @@ class DAppHooksUseCase extends ReactiveUseCase { final ErrorUseCase _errorUseCase; final MinerUseCase _minerUseCase; final ContextLessTranslationUseCase _contextLessTranslationUseCase; + final BlueberryRingBackgroundSyncUseCase _blueberryRingBackgroundSyncUseCase; // Context less translation, This should be only used for BG functions String cTranslate(String key) => @@ -371,14 +374,14 @@ class DAppHooksUseCase extends ReactiveUseCase { Future executeBlueberryAutoSync( {required Account account, required List selectedMinerListId, - required DateTime minerAutoClaimTime}) async { - await claimMiners( - selectedMinerListId: dappHooksData.value.minerHooks.selectedMiners, + required DateTime ringAutoSyncTime}) async { + await syncBlueberryRingSync( + selectedRingsListId: dappHooksData.value.minerHooks.selectedMiners, account: account, - minerAutoClaimTime: minerAutoClaimTime, + ringAutoSyncTime: ringAutoSyncTime, ); return await scheduleBlueberryAutoSyncTransaction( - minerAutoClaimTime, + ringAutoSyncTime, ); } @@ -508,21 +511,21 @@ class DAppHooksUseCase extends ReactiveUseCase { } // List of miners - Future syncBlueberryRing( - {required List selectedMinerListId, + Future syncBlueberryRingSync( + {required List selectedRingsListId, required Account account, - required DateTime minerAutoClaimTime}) async { + required DateTime ringAutoSyncTime}) async { try { AXSNotification().showNotification(cTranslate('auto_sync_started'), null); - if (selectedMinerListId.isEmpty) { + if (selectedRingsListId.isEmpty) { AXSNotification().showNotification( cTranslate('no_rings_selected_notification_title'), cTranslate('no_rings_selected_notification_text'), ); } else { - final ableToClaim = await _minerUseCase.claimMinersReward( - selectedMinerListId: selectedMinerListId, + final ableToClaim = await _blueberryRingBackgroundSyncUseCase.syncRings( + selectedRingsListId: selectedRingsListId, account: account, showNotification: AXSNotification().showLowPriorityNotification, translate: cTranslate); @@ -539,7 +542,7 @@ class DAppHooksUseCase extends ReactiveUseCase { ); } // Updating now date time + 1 day to set the timer for tomorrow - updateAutoClaimTime(minerAutoClaimTime); + updateAutoClaimTime(ringAutoSyncTime); } } catch (e) { _errorUseCase.handleBackgroundServiceError( diff --git a/packages/shared b/packages/shared index 40d92209..f949a958 160000 --- a/packages/shared +++ b/packages/shared @@ -1 +1 @@ -Subproject commit 40d922091d3f6c514b4e77677e919728816008c1 +Subproject commit f949a95849bf50e688ccb0ca8e312eb598210317